merge -s ours from froyo-release so that upgrading to gingerbread is a git fast-forward
Change-Id: I199d5b50435f5d31038287831521a73a60abbb14
diff --git a/.gitignore b/.gitignore
index d5b85d3..7430b9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
*.so
.deps
.libs
+.dirstamp
Makefile
Makefile.in
aclocal.m4
@@ -26,16 +27,22 @@
ylwrap
bluez.pc
-include/bluetooth
+lib/bluetooth
+src/builtin.h
src/bluetoothd
+src/bluetooth.exp
+src/bluetooth.ver
audio/telephony.c
scripts/bluetooth.rules
+scripts/97-bluetooth.rules
+scripts/97-bluetooth-hid2hci.rules
sbc/sbcdec
sbc/sbcenc
sbc/sbcinfo
sbc/sbctester
+tracer/hcitrace
tools/avctrl
tools/avinfo
tools/bccmd
@@ -48,10 +55,10 @@
tools/hcisecfilter
tools/hcitool
tools/hid2hci
+tools/rfcomm
tools/l2ping
tools/ppporc
tools/sdptool
-audio/ipctest
cups/bluetooth
test/agent
test/bdaddr
@@ -62,14 +69,15 @@
test/l2test
test/rctest
test/scotest
+test/gaptest
test/sdptest
test/lmptest
+test/ipctest
test/btiotest
-rfcomm/rfcomm
+test/test-textfile
compat/dund
compat/hidd
compat/pand
-common/test_textfile
doc/*.bak
doc/*.stamp
@@ -80,4 +88,3 @@
doc/xml
doc/html
src/bluetoothd.8
-src/hcid.conf.5
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..2d7ce47
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,5 @@
+Luiz Augusto von Dentz <luiz.dentz-von@nokia.com> <luiz.dentz-von@nokia.com>
+Vinicius Costa Gomes <vinicius.gomes@openbossa.org> <vinicius.gomes@openbossa.org>
+Elvis Pfützenreuter <epx@signove.com> <epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es> <scarot@libresoft.es>
+José Antonio Santos Cadenas <santoscadenas@gmail.com> <santoscadenas@gmail.com>
diff --git a/AUTHORS b/AUTHORS
index cd0189e..8e0a012 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -44,3 +44,9 @@
Ilya Rubtsov <lusyaru@gmail.com>
Mario Limonciello <mario_limonciello@dell.com>
Filippo Giunchedi <filippo@esaurito.net>
+Jaikumar Ganesh <jaikumar@google.com>
+Elvis Pfutzenreuter <epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es>
+José Antonio Santos Cadenas <jcaden@libresoft.es>
+Francisco Alecrim <francisco.alecrim@openbossa.org>
+Daniel Orstadius <daniel.orstadius@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index e7066b8..4aa4589 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,176 @@
+ver 4.69:
+ Fix issue with calling g_option_context_free() twice.
+ Fix inconsistencies with initial LE commands and events.
+ Add support for telephony ClearLastNumber method.
+ Add support for network server interface.
+
+ver 4.68:
+ Fix initialization of adapters in RAW mode.
+ Fix signal strength for HFP in Maemo's telephony support.
+ Add support for following the radio state via Maemo's MCE.
+ Add initial set of LE commands and events definitions.
+ Add mode option for L2CAP sockets to the BtIO API.
+
+ver 4.67:
+ Fix issue with authentication reply when bonding already completed.
+ Fix issue with not canceling authentication when bonding fails.
+ Fix issue with changed combination keys and temporary storage.
+ Fix issue with sdp_get_supp_feat library function.
+ Fix issue with missing unblock on device removal.
+ Fix issue with not waiting for mode change completion.
+ Add ARMv6 optimized version of analysis filter for SBC encoder.
+
+ver 4.66:
+ Fix regression with full debug enabling via SIGUSR2.
+ Fix redundant speaker/microphone gains being sent.
+ Fix not emitting PropertyChanged for SpeakerGain/MicrophoneGain.
+ Fix issue with storage usage when a record is not found in memory.
+ Fix issue with DiscoverServices not retrieving any records.
+ Fix audio profile disconnection order to match whitepaper.
+ Fix auto-accept confirmation when local agent has NoInputNoOutput.
+ Fix remote just-works SSP when MITM protection is required.
+ Fix performing dedicated bonding without MITM requirement.
+ Add support for storing debug link keys in runtime memory.
+
+ver 4.65:
+ Fix issues with general bonding being default setting now.
+ Fix driver removal upon device removal.
+ Add new "Blocked" property to device objects.
+ Add hciconfig support for blacklisting.
+ Add support for dynamic debug feature.
+
+ver 4.64:
+ Fix invalid memory access in headset_get_nrec function.
+ Fix issue with disconnect event on higher protocol layers.
+ Fix issue with list parsing in sdp_set_supp_features function.
+ Fix device object reference counting for SDP browse requests.
+ Add missing memory checks whenever memory is allocated for SDP.
+ Add support for exporting local services via D-Bus.
+ Add more L2CAP Enhanced Retransmission test options.
+
+ver 4.63:
+ Fix avdtp_abort not canceling pending requests.
+ Fix stale connection when abort gets rejected.
+
+ver 4.62:
+ Fix accidental symbol breakage with inquiry transmit power.
+ Fix using invalid data from previous headset connection.
+ Fix double free on AVDTP Abort response.
+ Fix possible crash while verifying AVDTP version.
+ Fix missing inuse flag when AVDTP stream is configured.
+ Add support for Bluetooth controller types.
+
+ver 4.61:
+ Fix issues with Read Inquiry Response Transmit Power Level.
+ Fix possible invalid read when removing a temporary device.
+ Fix mode restoration when remember_powered is false.
+ Fix conference call releasing in telephony-maemo.
+ Fix segmentation fault with authorization during headset disconnects.
+ Add support for handling unanswered AVDTP request on disconnect.
+ Add support for handling Inquiry Response Transmit Power Level.
+ Add support for caching of remote host features.
+ Add preliminary voice dialing support for HSP.
+
+ver 4.60:
+ Fix voice mailbox number reading from SIM.
+ Fix some races with D-Bus mainloop integration.
+ Add helpers for D-Bus signal watches.
+
+ver 4.59:
+ Add values for Bluetooth 4.0 specification.
+ Add SDP functions for HDP support.
+ Add test scripts for input and audio.
+ Fix missing close on BtIO create_io function.
+ Fix sending incorrect AVDTP commands after timeout occurs.
+ Fix timer removal when device disconnects unexpectedly.
+ Fix Extended Inquiry Response record for Device ID.
+
+ver 4.58:
+ Fix crash when adapter agent exists during authentication.
+ Fix CK-20W quirks for play and pause events.
+
+ver 4.57:
+ Fix unloading of drivers for uninitialized adapters.
+ Fix debug message to use requested and not opened SEID.
+ Fix codec selection for GStreamer plugin.
+ Fix deleting of SDP records during service updates.
+ Fix deleting of SDP records when a device is removed.
+ Fix handling when the SDP record is modified on remote device.
+ Fix potential buffer overflow by using snprintf instead of sprintf.
+ Fix const declarations for some storage function parameters.
+
+ver 4.56:
+ Add missing values from Bluetooth 3.0 specification.
+ Add proper tracking of device paired status.
+ Fix tracking of devices without permanently stored link key.
+ Fix issue with link key removal after connection failures.
+ Fix legacy pairing information based on remote host features.
+ Fix off-by-one issue with AVDTP capability parsing.
+ Fix AVRCP, AVCTP, AVDTP, A2DP and HFP version numbers.
+ Fix agent canceling before calling agent_destroy.
+ Fix service record parsing with an empty UUID list.
+ Fix various SDP related memory leaks.
+
+ver 4.55:
+ Add support for POSIX capabilities dropping.
+ Add special quirk for the Nokia CK-20W car kit.
+ Fix error code handling for AVDTP SetConfiguration response.
+ Fix updating out of range list when RSSI hasn't changed.
+ Fix various memory leaks and unnecessary error checks.
+
+ver 4.54:
+ Add introspection interface to output of introspection calls.
+ Fix stream handling when media transport disconnects prematurely.
+ Fix command timeout handling when there's no stream.
+ Fix headset_suspend_stream behavior for invalid states
+ Fix issue with AVDTP ABORTING state transition.
+ Fix issue with AVDTP suspend while closing.
+
+ver 4.53:
+ Fix issue with telephony connection state notifications.
+ Fix AVDTP stream leak for invalid media transport config.
+ Fix audio connection authorization handling with timeouts.
+ Fix race condition in authorizing audio connections.
+ Fix device authorized setting for AVRCP-only connections.
+ Fix duplicate attempts from device to connect signal channel.
+
+ver 4.52:
+ Add AVCTP support to test utility.
+ Fix AVDTP Abort when transport closes before response.
+ Fix authorization when the audio profiles are slow to connect.
+ Fix potential AVDTP reference leaks.
+
+ver 4.51:
+ Add utility for basic AVDTP testing.
+ Add support for configuring L2CAP FCS option.
+ Fix discovery mode for CUPS 1.4.x and later.
+ Fix global state tracking of audio service.
+ Fix last issues with the new build system.
+
+ver 4.50:
+ Fix issue with missing manual pages in distribution.
+ Fix issue with the configuration and state directories.
+ Fix issue with creating include directory.
+ Fix dependencies of include file generation.
+
+ver 4.49:
+ Add simple test program for basic GAP testing.
+ Add support for confirmation requests to agent example.
+ Add support for full non-recursive build.
+ Add five millisecond delay for Simple Pairing auto-accept.
+ Fix Class of Device setting when InitiallyPowered=false.
+
+ver 4.48:
+ Add library function for comparing UUID values.
+ Add support for creating all plugins as builtins.
+ Add support for async handling of service class changes.
+ Add support for source interface to audio IPC.
+ Fix device name settings when device is off or down.
+ Fix issue with enabled SCO server when not necessary.
+ Fix missing D-Bus access policy for CUPS backend.
+ Fix discovery results of CUPS backend.
+ Fix initialization handling of Maemo telephony.
+
ver 4.47:
Add support for RFKILL unblock handling.
Add support for serial proxy configurations.
diff --git a/Makefile.am b/Makefile.am
index c4c6322..f4bf87d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,16 +1,334 @@
-SUBDIRS = include lib sbc gdbus common plugins src client\
- network serial input audio tools \
- rfcomm compat cups test scripts doc
+AM_MAKEFLAGS = --no-print-directory
-EXTRA_DIST = bluez.m4
+lib_LTLIBRARIES =
+
+noinst_LTLIBRARIES =
+
+bin_PROGRAMS =
+
+sbin_PROGRAMS =
+
+noinst_PROGRAMS =
+
+dist_man_MANS =
+
+dist_noinst_MANS =
+
+CLEANFILES =
+
+EXTRA_DIST =
+
+includedir = @includedir@/bluetooth
+
+include_HEADERS =
+
+if CONFIGFILES
+dbusdir = $(sysconfdir)/dbus-1/system.d
+
+dbus_DATA = src/bluetooth.conf
+
+confdir = $(sysconfdir)/bluetooth
+
+conf_DATA =
+
+statedir = $(localstatedir)/lib/bluetooth
+
+state_DATA =
+endif
+
+plugindir = $(libdir)/bluetooth/plugins
+
+plugin_LTLIBRARIES =
+
+
+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
+local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
+
+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_libbluetooth_la_LDFLAGS = -version-info 12:0:9
+lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
+
+CLEANFILES += $(local_headers)
+
+
+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_neon.h sbc/sbc_primitives_neon.c \
+ sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
+
+sbc_libsbc_la_CFLAGS = -finline-functions -fgcse-after-reload \
+ -funswitch-loops -funroll-loops
+
+noinst_PROGRAMS += sbc/sbcinfo sbc/sbcdec sbc/sbcenc
+
+sbc_sbcdec_SOURCES = sbc/sbcdec.c sbc/formats.h
+sbc_sbcdec_LDADD = sbc/libsbc.la
+
+sbc_sbcenc_SOURCES = sbc/sbcenc.c sbc/formats.h
+sbc_sbcenc_LDADD = sbc/libsbc.la
+
+if SNDFILE
+noinst_PROGRAMS += sbc/sbctester
+
+sbc_sbctester_LDADD = @SNDFILE_LIBS@ -lm
+sbc_sbctest_CFLAGS = @SNDFILE_CFLAGS@
+endif
+endif
+
+
+if NETLINK
+plugin_LTLIBRARIES += plugins/netlink.la
+
+plugins_netlink_la_LIBADD = @NETLINK_LIBS@
+plugins_netlink_la_LDFLAGS = -module -avoid-version -no-undefined
+plugins_netlink_la_CFLAGS = -fvisibility=hidden @DBUS_CFLAGS@ \
+ @GLIB_CFLAGS@ @NETLINK_CFLAGS@
+endif
+
+gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/object.c gdbus/watch.c
+
+builtin_modules =
+builtin_sources =
+builtin_nodist =
+
+if PNATPLUGIN
+builtin_modules += pnat
+builtin_sources += plugins/pnat.c
+endif
+
+if ECHOPLUGIN
+builtin_modules += echo
+builtin_sources += plugins/echo.c
+endif
+
+if AUDIOPLUGIN
+builtin_modules += audio
+builtin_sources += audio/main.c \
+ 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/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/telephony.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 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
+
+builtin_modules += hciops
+builtin_sources += plugins/hciops.c
+
+builtin_modules += hal
+builtin_sources += plugins/hal.c
+
+builtin_modules += storage
+builtin_sources += plugins/storage.c
+
+if MAEMO6PLUGIN
+builtin_modules += maemo6
+builtin_sources += plugins/maemo6.c
+endif
+
+sbin_PROGRAMS += src/bluetoothd
+
+src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
+ src/main.c src/log.h src/log.c \
+ src/security.c src/rfkill.c src/hcid.h src/sdpd.h \
+ src/sdpd-server.c src/sdpd-request.c \
+ src/sdpd-service.c src/sdpd-database.c \
+ src/sdp-xml.h src/sdp-xml.c src/btio.h src/btio.c \
+ src/textfile.h src/textfile.c \
+ src/glib-helper.h src/glib-helper.c \
+ src/oui.h src/oui.c src/uinput.h src/ppoll.h \
+ src/plugin.h src/plugin.c \
+ src/storage.h src/storage.c \
+ src/agent.h src/agent.c \
+ src/error.h src/error.c \
+ src/manager.h src/manager.c \
+ src/adapter.h src/adapter.c \
+ src/device.h src/device.c \
+ src/dbus-common.c src/dbus-common.h \
+ src/dbus-hci.h src/dbus-hci.c
+src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
+ @CAPNG_LIBS@ -ldl
+src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
+ -Wl,--version-script=src/bluetooth.ver
+src_bluetoothd_DEPENDENCIES = src/bluetooth.ver lib/libbluetooth.la
+
+builtin_files = src/builtin.h $(builtin_nodist)
+
+nodist_src_bluetoothd_SOURCES = $(builtin_files)
+
+CLEANFILES += src/bluetooth.ver src/bluetooth.exp $(builtin_files)
+
+man_MANS = src/bluetoothd.8
+
+if CONFIGFILES
+conf_DATA += src/main.conf
+endif
+
+EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
+ 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
+
+
+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 = -module -avoid-version #-export-symbols-regex [_]*snd_pcm_.*
+audio_libasound_module_pcm_bluetooth_la_LIBADD = sbc/libsbc.la \
+ lib/libbluetooth.la @ALSA_LIBS@
+audio_libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+
+audio_libasound_module_ctl_bluetooth_la_SOURCES = audio/ctl_bluetooth.c \
+ audio/rtp.h audio/ipc.h audio/ipc.c
+audio_libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_ctl_.*
+audio_libasound_module_ctl_bluetooth_la_LIBADD = lib/libbluetooth.la @ALSA_LIBS@
+audio_libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+
+if CONFIGFILES
+alsaconfdir = $(sysconfdir)/alsa
+
+alsaconf_DATA = audio/bluetooth.conf
+endif
+endif
+
+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 = -module -avoid-version
+audio_libgstbluetooth_la_LIBADD = sbc/libsbc.la lib/libbluetooth.la \
+ @GSTREAMER_LIBS@ -lgstaudio-0.10 -lgstrtp-0.10
+audio_libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \
+ $(AM_CFLAGS) @GSTREAMER_CFLAGS@
+endif
+endif
+
+EXTRA_DIST += audio/bluetooth.conf
+
+
+include Makefile.tools
+
+if UDEVRULES
+rulesdir = @UDEV_DATADIR@
+
+udev_files = scripts/bluetooth.rules
+
+if HID2HCI
+udev_files += scripts/bluetooth-hid2hci.rules
+endif
+
+if PCMCIA
+udev_files += scripts/bluetooth-serial.rules
+endif
+
+rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file)))
+endif
+
+CLEANFILES += $(rules_DATA)
+
+EXTRA_DIST += scripts/bluetooth.rules \
+ scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules
+
+if PCMCIA
+udevdir = $(libexecdir)/udev
+
+dist_udev_SCRIPTS = scripts/bluetooth_serial
+endif
+
+EXTRA_DIST += doc/manager-api.txt \
+ doc/adapter-api.txt doc/device-api.txt \
+ doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
+ doc/serial-api.txt doc/network-api.txt \
+ doc/input-api.txt doc/audio-api.txt doc/control-api.txt
+
+AM_YFLAGS = -d
+
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \
+ -DBLUETOOTH_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
+
+INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
+ -I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus
+
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = bluez.pc
-DISTCHECK_CONFIGURE_FLAGS = --disable-gtk-doc \
- --disable-udevrules
+DISTCHECK_CONFIGURE_FLAGS = --disable-udevrules
DISTCLEANFILES = $(pkgconfig_DATA)
@@ -18,3 +336,34 @@
aclocal.m4 configure config.h.in config.sub config.guess \
ltmain.sh depcomp compile missing install-sh mkinstalldirs ylwrap
+src/plugin.$(OBJEXT): src/builtin.h
+
+src/builtin.h: src/genbuiltin $(builtin_sources)
+ $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
+
+src/bluetooth.exp: $(src_bluetoothd_OBJECTS)
+ $(AM_V_GEN)$(NM) $^ | $(AWK) '{ print $$3 }' | sort -u | \
+ $(EGREP) -e '^btd_' -e '^g_dbus_' > $@
+ $(AM_V_at)echo -e "info" >> $@
+ $(AM_V_at)echo -e "error" >> $@
+ $(AM_V_at)echo -e "debug" >> $@
+
+src/bluetooth.ver: src/bluetooth.exp
+ $(AM_V_at)echo "{ global:" > $@
+ $(AM_V_GEN)$(SED) -e "s/\(.*\)/\1;/" $< >> $@
+ $(AM_V_at)echo "local: *; };" >> $@
+
+audio/telephony.c: audio/@TELEPHONY_DRIVER@
+ $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+
+scripts/%.rules:
+ $(AM_V_GEN)cp $(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_srcdir)/$< $@
+
+clean-local: lib/bluetooth
+ @$(RM) -r $<
diff --git a/Makefile.tools b/Makefile.tools
new file mode 100644
index 0000000..2dbf925
--- /dev/null
+++ b/Makefile.tools
@@ -0,0 +1,230 @@
+
+if TOOLS
+if CONFIGFILES
+conf_DATA += tools/rfcomm.conf
+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_rfcomm_SOURCES = tools/main.c tools/parser.y tools/lexer.l \
+ tools/kword.h tools/kword.c
+EXTRA_tools_rfcomm_SOURCES = tools/parser.h tools/parser.c \
+ tools/lexer.c
+tools_rfcomm_LDADD = lib/libbluetooth.la
+
+tools_l2ping_LDADD = lib/libbluetooth.la
+
+tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
+ tools/hciattach_st.c \
+ tools/hciattach_ti.c \
+ tools/hciattach_tialt.c
+tools_hciattach_LDADD = lib/libbluetooth.la
+
+tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
+ src/textfile.h src/textfile.c
+tools_hciconfig_LDADD = lib/libbluetooth.la
+
+tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \
+ src/textfile.h src/textfile.c
+tools_hcitool_LDADD = lib/libbluetooth.la
+
+tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
+tools_sdptool_LDADD = lib/libbluetooth.la
+
+tools_ciptool_LDADD = lib/libbluetooth.la
+
+tools_avinfo_LDADD = lib/libbluetooth.la
+
+tools_ppporc_LDADD = lib/libbluetooth.la
+
+tools_hcieventmask_LDADD = lib/libbluetooth.la
+
+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
+
+CLEANFILES += tools/lexer.c tools/parser.c tools/parser.h
+
+EXTRA_DIST += tools/rfcomm.conf
+
+if TRACER
+sbin_PROGRAMS += tracer/hcitrace
+
+tracer_hcitrace_SOURCES = tracer/main.c
+tracer_hcitrace_LDADD = lib/libbluetooth.la \
+ @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@
+tracer_hcitrace_DEPENDENCIES = lib/libbluetooth.la
+endif
+
+if BCCMD
+sbin_PROGRAMS += tools/bccmd
+
+tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \
+ tools/csr_hci.c tools/csr_h4.c tools/csr_3wire.c \
+ tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
+tools_bccmd_LDADD = lib/libbluetooth.la
+
+if USB
+tools_bccmd_SOURCES += tools/csr_usb.c
+tools_bccmd_LDADD += @USB_LIBS@
+endif
+
+dist_man_MANS += tools/bccmd.8
+else
+EXTRA_DIST += tools/bccmd.8
+endif
+
+if HID2HCI
+sbin_PROGRAMS += tools/hid2hci
+
+tools_hid2hci_LDADD = @USB_LIBS@
+
+dist_man_MANS += tools/hid2hci.8
+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@
+endif
+
+EXTRA_DIST += tools/dfubabel.1 tools/avctrl.8
+
+
+if CUPS
+cupsdir = $(libdir)/cups/backend
+
+cups_PROGRAMS = cups/bluetooth
+
+cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \
+ cups/sdp.c cups/spp.c cups/hcrp.c
+
+cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth.la
+endif
+
+
+if TEST
+sbin_PROGRAMS += test/hciemu
+
+bin_PROGRAMS += test/l2test test/rctest
+
+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_hciemu_LDADD = @GLIB_LIBS@ lib/libbluetooth.la
+
+test_l2test_LDADD = lib/libbluetooth.la
+
+test_rctest_LDADD = lib/libbluetooth.la
+
+test_gaptest_LDADD = @DBUS_LIBS@
+
+test_sdptest_LDADD = lib/libbluetooth.la
+
+test_scotest_LDADD = lib/libbluetooth.la
+
+test_attest_LDADD = lib/libbluetooth.la
+
+test_hstest_LDADD = lib/libbluetooth.la
+
+test_avtest_LDADD = lib/libbluetooth.la
+
+test_lmptest_LDADD = lib/libbluetooth.la
+
+test_ipctest_SOURCES = test/ipctest.c audio/ipc.h audio/ipc.c
+test_ipctest_LDADD= @GLIB_LIBS@ sbc/libsbc.la
+
+test_bdaddr_SOURCES = test/bdaddr.c src/oui.h src/oui.c
+test_bdaddr_LDADD = lib/libbluetooth.la
+
+test_agent_LDADD = @DBUS_LIBS@
+
+test_btiotest_SOURCES = test/btiotest.c src/btio.h src/btio.c
+test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth.la
+
+test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c
+
+dist_man_MANS += test/rctest.1 test/hciemu.1
+
+EXTRA_DIST += test/bdaddr.8
+else
+EXTRA_DIST += test/rctest.1 test/hciemu.1 test/bdaddr.8
+endif
+
+EXTRA_DIST += test/apitest test/hsplay test/hsmicro test/dbusdef.py \
+ test/monitor-bluetooth test/list-devices test/test-discovery \
+ test/test-manager test/test-adapter test/test-device \
+ test/test-service test/test-serial test/test-telephony \
+ test/test-network test/simple-agent test/simple-service \
+ test/test-audio test/test-input \
+ test/service-record.dtd test/service-did.xml \
+ test/service-spp.xml test/service-opp.xml test/service-ftp.xml
+
+
+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.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.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.la
+
+dist_man_MANS += compat/dund.1
+else
+EXTRA_DIST += compat/dund.1
+endif
diff --git a/README b/README
index 3cc6547..77778e0 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
-Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
Compilation and installation
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
new file mode 100644
index 0000000..b6bef4a
--- /dev/null
+++ b/ThirdPartyProject.prop
@@ -0,0 +1,10 @@
+# Copyright 2010 Google Inc. All Rights Reserved.
+#Fri Jul 16 10:03:08 PDT 2010
+currentVersion=Unknown
+version=4.69
+isNative=true
+feedurl=ChangeLog
+name=bluez-utils
+keywords=bluez-utils
+onDevice=true
+homepage=www.bluez.org
diff --git a/acinclude.m4 b/acinclude.m4
index 248fed3..f5fdd66 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -25,34 +25,6 @@
fi
])
-AC_DEFUN([GTK_DOC_CHECK], [
- AC_ARG_WITH([html-dir],
- AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),,
- [with_html_dir='${datadir}/gtk-doc/html'])
- HTML_DIR="$with_html_dir"
- AC_SUBST([HTML_DIR])
-
- AC_ARG_ENABLE([gtk-doc],
- AS_HELP_STRING([--enable-gtk-doc], [use gtk-doc to build documentation [[default=no]]]),,
- [enable_gtk_doc=no])
-
- if test x$enable_gtk_doc = xyes; then
- ifelse([$1],[],
- [PKG_CHECK_EXISTS([gtk-doc],,
- AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))],
- [PKG_CHECK_EXISTS([gtk-doc >= $1],,
- AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build gtk-doc]))])
- fi
-
- AC_MSG_CHECKING([whether to build gtk-doc documentation])
- AC_MSG_RESULT($enable_gtk_doc)
-
- AC_PATH_PROGS(GTKDOC_CHECK,gtkdoc-check,)
-
- AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes])
- AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"])
-])
-
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.]))
@@ -126,6 +98,10 @@
AC_CHECK_LIB(dbus-1, dbus_watch_get_unix_fd, dummy=yes,
AC_DEFINE(NEED_DBUS_WATCH_GET_UNIX_FD, 1,
[Define to 1 if you need the dbus_watch_get_unix_fd() function.]))
+ AC_CHECK_LIB(dbus-1, dbus_connection_can_send_type, dummy=yes,
+ AC_DEFINE(NEED_DBUS_CONNECTION_CAN_SEND_TYPE, 1,
+ [Define to 1 if you need the dbus_connection_can_send_type() function.]
+))
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
])
@@ -170,12 +146,6 @@
[Define to 1 if you need the usb_interrupt_read() function.]))
])
-AC_DEFUN([AC_PATH_NETLINK], [
- PKG_CHECK_MODULES(NETLINK, libnl-1, netlink_found=yes, netlink_found=no)
- AC_SUBST(NETLINK_CFLAGS)
- AC_SUBST(NETLINK_LIBS)
-])
-
AC_DEFUN([AC_PATH_SNDFILE], [
PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no)
AC_SUBST(SNDFILE_CFLAGS)
@@ -188,7 +158,6 @@
fortify_enable=yes
pie_enable=yes
sndfile_enable=${sndfile_found}
- netlink_enable=no
hal_enable=${hal_found}
usb_enable=${usb_found}
alsa_enable=${alsa_found}
@@ -198,6 +167,8 @@
serial_enable=yes
network_enable=yes
service_enable=yes
+ pnat_enable=no
+ tracer_enable=no
tools_enable=yes
hidd_enable=no
pand_enable=no
@@ -208,10 +179,10 @@
pcmcia_enable=no
hid2hci_enable=no
dfutool_enable=no
- manpages_enable=yes
udevrules_enable=yes
configfiles_enable=yes
telephony_driver=dummy
+ maemo6_enable=no
AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
optimization_enable=${enableval}
@@ -245,6 +216,10 @@
service_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}
])
@@ -257,8 +232,8 @@
usb_enable=${enableval}
])
- AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink], [enable NETLINK support]), [
- netlink_enable=${enableval}
+ AC_ARG_ENABLE(tracer, AC_HELP_STRING([--enable-tracer], [install Tracing daemon]), [
+ tracer_enable=${enableval}
])
AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools], [install Bluetooth utilities]), [
@@ -301,10 +276,6 @@
test_enable=${enableval}
])
- AC_ARG_ENABLE(manpages, AC_HELP_STRING([--enable-manpages], [install Bluetooth manual pages]), [
- manpages_enable=${enableval}
- ])
-
AC_ARG_ENABLE(udevrules, AC_HELP_STRING([--enable-udevrules], [install Bluetooth udev rules]), [
udevrules_enable=${enableval}
])
@@ -323,6 +294,10 @@
AC_SUBST([TELEPHONY_DRIVER], [telephony-${telephony_driver}.c])
+ AC_ARG_ENABLE(maemo6, AC_HELP_STRING([--enable-maemo6], [compile with maemo6 plugin]), [
+ maemo6_enable=${enableval}
+ ])
+
if (test "${fortify_enable}" = "yes"); then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
fi
@@ -344,19 +319,10 @@
AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.])
fi
- AC_SUBST([BLUEZ_CFLAGS], ['-I$(top_builddir)/include'])
- AC_SUBST([BLUEZ_LIBS], ['$(top_builddir)/lib/libbluetooth.la'])
-
- AC_SUBST([GDBUS_CFLAGS], ['-I$(top_srcdir)/gdbus'])
- AC_SUBST([GDBUS_LIBS], ['$(top_builddir)/gdbus/libgdbus.la'])
-
- AC_SUBST([SBC_CFLAGS], ['-I$(top_srcdir)/sbc'])
- AC_SUBST([SBC_LIBS], ['$(top_builddir)/sbc/libsbc.la'])
-
AM_CONDITIONAL(SNDFILE, test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes")
- AM_CONDITIONAL(NETLINK, test "${netlink_enable}" = "yes" && test "${netlink_found}" = "yes")
AM_CONDITIONAL(USB, test "${usb_enable}" = "yes" && test "${usb_found}" = "yes")
- AM_CONDITIONAL(SBC, test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "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")
@@ -364,6 +330,9 @@
AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
+ AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
+ AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
+ AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes")
AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes")
AM_CONDITIONAL(DUND, test "${dund_enable}" = "yes")
@@ -374,7 +343,7 @@
AM_CONDITIONAL(PCMCIA, test "${pcmcia_enable}" = "yes")
AM_CONDITIONAL(HID2HCI, test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes")
AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes")
- AM_CONDITIONAL(MANPAGES, test "${manpages_enable}" = "yes")
AM_CONDITIONAL(UDEVRULES, test "${udevrules_enable}" = "yes")
AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" = "yes")
+ AM_CONDITIONAL(MAEMO6PLUGIN, test "${maemo6_enable}" = "yes")
])
diff --git a/audio/Android.mk b/audio/Android.mk
index cc93441..483db12 100755
--- a/audio/Android.mk
+++ b/audio/Android.mk
@@ -21,15 +21,14 @@
unix.c
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" \
+ -DVERSION=\"4.69\" \
-DSTORAGEDIR=\"/data/misc/bluetoothd\" \
-DCONFIGDIR=\"/etc/bluetooth\" \
-DANDROID \
-D__S_IFREG=0100000 # missing from bionic stat.h
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
$(LOCAL_PATH)/../gdbus \
$(LOCAL_PATH)/../src \
$(call include-path-for, glib) \
diff --git a/audio/Makefile.am b/audio/Makefile.am
deleted file mode 100644
index 52ad212..0000000
--- a/audio/Makefile.am
+++ /dev/null
@@ -1,87 +0,0 @@
-
-BUILT_SOURCES = telephony.c
-
-if AUDIOPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = audio.la
-
-audio_la_SOURCES = main.c \
- ipc.h ipc.c unix.h unix.c manager.h manager.c telephony.h \
- device.h device.c headset.h headset.c gateway.h gateway.c \
- avdtp.h avdtp.c a2dp.h a2dp.c sink.h sink.c source.h source.c \
- control.h control.c
-
-nodist_audio_la_SOURCES = $(BUILT_SOURCES)
-
-audio_la_LDFLAGS = -module -avoid-version -no-undefined
-
-LDADD = $(top_builddir)/common/libhelper.a \
- @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-
-if ALSA
-alsadir = $(libdir)/alsa-lib
-
-alsa_LTLIBRARIES = libasound_module_pcm_bluetooth.la libasound_module_ctl_bluetooth.la
-
-libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c rtp.h ipc.h ipc.c
-libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_pcm_.*
-libasound_module_pcm_bluetooth_la_LIBADD = @SBC_LIBS@ @BLUEZ_LIBS@ @ALSA_LIBS@
-libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @BLUEZ_CFLAGS@ @SBC_CFLAGS@
-
-libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c rtp.h ipc.h ipc.c
-libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_ctl_.*
-libasound_module_ctl_bluetooth_la_LIBADD = @BLUEZ_LIBS@ @ALSA_LIBS@
-libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @BLUEZ_CFLAGS@
-
-if CONFIGFILES
-alsaconfdir = $(sysconfdir)/alsa
-
-alsaconf_DATA = bluetooth.conf
-endif
-endif
-
-if GSTREAMER
-gstreamerdir = $(libdir)/gstreamer-0.10
-
-gstreamer_LTLIBRARIES = libgstbluetooth.la
-
-libgstbluetooth_la_SOURCES = gstbluetooth.c \
- gstsbcenc.h gstsbcenc.c \
- gstsbcdec.h gstsbcdec.c \
- gstsbcparse.h gstsbcparse.c \
- gstavdtpsink.h gstavdtpsink.c \
- gsta2dpsink.h gsta2dpsink.c \
- gstsbcutil.h gstsbcutil.c \
- gstrtpsbcpay.h gstrtpsbcpay.c \
- rtp.h ipc.h ipc.c
-libgstbluetooth_la_LDFLAGS = -module -avoid-version
-libgstbluetooth_la_LIBADD = @SBC_LIBS@ @BLUEZ_LIBS@ @GSTREAMER_LIBS@ \
- -lgstaudio-0.10 -lgstrtp-0.10
-libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \
- @GSTREAMER_CFLAGS@ @BLUEZ_CFLAGS@ @SBC_CFLAGS@
-endif
-endif
-
-noinst_LTLIBRARIES = libipc.la
-
-libipc_la_SOURCES = ipc.h ipc.c
-
-noinst_PROGRAMS = ipctest
-
-ipctest_LDADD= libipc.la @SBC_LIBS@ @GLIB_LIBS@
-
-AM_CFLAGS = -fvisibility=hidden @SBC_CFLAGS@ \
- @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-CLEANFILES = $(BUILT_SOURCES)
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = audio.conf telephony-dummy.c telephony-maemo.c telephony-ofono.c \
- bluetooth.conf
-
-MAINTAINERCLEANFILES = Makefile.in
-
-telephony.c: @TELEPHONY_DRIVER@
- @if [ ! -e $@ ] ; then $(LN_S) $< $@ ; fi
diff --git a/audio/a2dp.c b/audio/a2dp.c
index 45be5d4..7b39c3d 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -36,12 +36,13 @@
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
-#include "logging.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 "sdpd.h"
@@ -65,6 +66,7 @@
struct avdtp *session;
struct avdtp_stream *stream;
guint suspend_timer;
+ gboolean delay_reporting;
gboolean locked;
gboolean suspending;
gboolean starting;
@@ -86,7 +88,6 @@
struct avdtp_error *err;
GSList *client_caps;
gboolean reconfigure;
- gboolean canceled;
gboolean start;
GSList *cb;
int ref;
@@ -100,6 +101,7 @@
GSList *sources;
uint32_t source_record_id;
uint32_t sink_record_id;
+ uint16_t version;
};
static GSList *servers = NULL;
@@ -110,14 +112,14 @@
{
setup->ref++;
- debug("setup_ref(%p): ref=%d", setup, setup->ref);
+ DBG("%p: ref=%d", setup, setup->ref);
return setup;
}
static void setup_free(struct a2dp_setup *s)
{
- debug("setup_free(%p)", s);
+ DBG("%p", s);
setups = g_slist_remove(setups, s);
if (s->session)
avdtp_unref(s->session);
@@ -130,7 +132,7 @@
{
setup->ref--;
- debug("setup_unref(%p): ref=%d", setup, setup->ref);
+ DBG("%p: ref=%d", setup, setup->ref);
if (setup->ref <= 0)
setup_free(setup);
@@ -286,14 +288,11 @@
{
struct a2dp_sep *a2dp_sep = user_data;
struct audio_device *dev;
- struct avdtp_service_capability *cap;
- struct avdtp_media_codec_capability *codec_cap;
- struct sbc_codec_cap *sbc_cap;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Set_Configuration_Ind", sep);
+ DBG("Sink %p: Set_Configuration_Ind", sep);
else
- debug("Source %p: Set_Configuration_Ind", sep);
+ DBG("Source %p: Set_Configuration_Ind", sep);
dev = a2dp_get_dev(session);
if (!dev) {
@@ -302,9 +301,19 @@
return FALSE;
}
- /* Check bipool range */
- for (codec_cap = NULL; caps; caps = g_slist_next(caps)) {
- cap = caps->data;
+ /* 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) {
+ *err = AVDTP_UNSUPPORTED_CONFIGURATION;
+ *category = AVDTP_DELAY_REPORTING;
+ return FALSE;
+ }
+
if (cap->category != AVDTP_MEDIA_CODEC)
continue;
@@ -324,8 +333,6 @@
*category = AVDTP_MEDIA_CODEC;
return FALSE;
}
-
- break;
}
avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
@@ -338,16 +345,17 @@
}
static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- GSList **caps, uint8_t *err, void *user_data)
+ 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)
- debug("Sink %p: Get_Capability_Ind", sep);
+ DBG("Sink %p: Get_Capability_Ind", sep);
else
- debug("Source %p: Get_Capability_Ind", sep);
+ DBG("Source %p: Get_Capability_Ind", sep);
*caps = NULL;
@@ -393,6 +401,13 @@
*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;
}
@@ -406,9 +421,9 @@
struct audio_device *dev;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Set_Configuration_Ind", sep);
+ DBG("Sink %p: Set_Configuration_Ind", sep);
else
- debug("Source %p: Set_Configuration_Ind", sep);
+ DBG("Source %p: Set_Configuration_Ind", sep);
dev = a2dp_get_dev(session);
if (!dev) {
@@ -417,6 +432,17 @@
return FALSE;
}
+ 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) {
+ *err = AVDTP_UNSUPPORTED_CONFIGURATION;
+ *category = AVDTP_DELAY_REPORTING;
+ return FALSE;
+ }
+ }
+
avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
a2dp_sep->stream = stream;
@@ -428,6 +454,7 @@
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;
@@ -435,9 +462,9 @@
struct mpeg_codec_cap mpeg_cap;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Get_Capability_Ind", sep);
+ DBG("Sink %p: Get_Capability_Ind", sep);
else
- debug("Source %p: Get_Capability_Ind", sep);
+ DBG("Source %p: Get_Capability_Ind", sep);
*caps = NULL;
@@ -472,6 +499,13 @@
*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;
}
@@ -485,9 +519,9 @@
int ret;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Set_Configuration_Cfm", sep);
+ DBG("Sink %p: Set_Configuration_Cfm", sep);
else
- debug("Source %p: Set_Configuration_Cfm", sep);
+ DBG("Source %p: Set_Configuration_Cfm", sep);
setup = find_setup_by_session(session);
@@ -527,9 +561,9 @@
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Get_Configuration_Ind", sep);
+ DBG("Sink %p: Get_Configuration_Ind", sep);
else
- debug("Source %p: Get_Configuration_Ind", sep);
+ DBG("Source %p: Get_Configuration_Ind", sep);
return TRUE;
}
@@ -540,9 +574,9 @@
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Set_Configuration_Cfm", sep);
+ DBG("Sink %p: Set_Configuration_Cfm", sep);
else
- debug("Source %p: Set_Configuration_Cfm", sep);
+ DBG("Source %p: Set_Configuration_Cfm", sep);
}
static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
@@ -552,9 +586,9 @@
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Open_Ind", sep);
+ DBG("Sink %p: Open_Ind", sep);
else
- debug("Source %p: Open_Ind", sep);
+ DBG("Source %p: Open_Ind", sep);
return TRUE;
}
@@ -566,21 +600,14 @@
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Open_Cfm", sep);
+ DBG("Sink %p: Open_Cfm", sep);
else
- debug("Source %p: Open_Cfm", sep);
+ DBG("Source %p: Open_Cfm", sep);
setup = find_setup_by_session(session);
if (!setup)
return;
- if (setup->canceled) {
- if (!err)
- avdtp_close(session, stream);
- setup_unref(setup);
- return;
- }
-
if (setup->reconfigure)
setup->reconfigure = FALSE;
@@ -613,17 +640,13 @@
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Start_Ind", sep);
+ DBG("Sink %p: Start_Ind", sep);
else
- debug("Source %p: Start_Ind", sep);
+ DBG("Source %p: Start_Ind", sep);
setup = find_setup_by_session(session);
- if (setup) {
- if (setup->canceled)
- setup_unref(setup);
- else
- finalize_resume(setup);
- }
+ if (setup)
+ finalize_resume(setup);
if (!a2dp_sep->locked) {
a2dp_sep->session = avdtp_ref(session);
@@ -643,21 +666,14 @@
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Start_Cfm", sep);
+ DBG("Sink %p: Start_Cfm", sep);
else
- debug("Source %p: Start_Cfm", sep);
+ DBG("Source %p: Start_Cfm", sep);
setup = find_setup_by_session(session);
if (!setup)
return;
- if (setup->canceled) {
- if (!err)
- avdtp_close(session, stream);
- setup_unref(setup);
- return;
- }
-
if (err) {
setup->stream = NULL;
setup->err = err;
@@ -673,9 +689,9 @@
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Suspend_Ind", sep);
+ DBG("Sink %p: Suspend_Ind", sep);
else
- debug("Source %p: Suspend_Ind", sep);
+ DBG("Source %p: Suspend_Ind", sep);
if (a2dp_sep->suspend_timer) {
g_source_remove(a2dp_sep->suspend_timer);
@@ -696,9 +712,9 @@
gboolean start;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Suspend_Cfm", sep);
+ DBG("Sink %p: Suspend_Cfm", sep);
else
- debug("Source %p: Suspend_Cfm", sep);
+ DBG("Source %p: Suspend_Cfm", sep);
a2dp_sep->suspending = FALSE;
@@ -739,9 +755,9 @@
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Close_Ind", sep);
+ DBG("Sink %p: Close_Ind", sep);
else
- debug("Source %p: Close_Ind", sep);
+ DBG("Source %p: Close_Ind", sep);
return TRUE;
}
@@ -804,19 +820,14 @@
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Close_Cfm", sep);
+ DBG("Sink %p: Close_Cfm", sep);
else
- debug("Source %p: Close_Cfm", sep);
+ DBG("Source %p: Close_Cfm", sep);
setup = find_setup_by_session(session);
if (!setup)
return;
- if (setup->canceled) {
- setup_unref(setup);
- return;
- }
-
if (err) {
setup->stream = NULL;
setup->err = err;
@@ -835,9 +846,9 @@
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Abort_Ind", sep);
+ DBG("Sink %p: Abort_Ind", sep);
else
- debug("Source %p: Abort_Ind", sep);
+ DBG("Source %p: Abort_Ind", sep);
a2dp_sep->stream = NULL;
@@ -852,9 +863,9 @@
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: Abort_Cfm", sep);
+ DBG("Sink %p: Abort_Cfm", sep);
else
- debug("Source %p: Abort_Cfm", sep);
+ DBG("Source %p: Abort_Cfm", sep);
setup = find_setup_by_session(session);
if (!setup)
@@ -869,9 +880,28 @@
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: ReConfigure_Ind", sep);
+ DBG("Sink %p: ReConfigure_Ind", sep);
else
- debug("Source %p: ReConfigure_Ind", sep);
+ DBG("Source %p: ReConfigure_Ind", 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;
}
@@ -883,21 +913,14 @@
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
- debug("Sink %p: ReConfigure_Cfm", sep);
+ DBG("Sink %p: ReConfigure_Cfm", sep);
else
- debug("Source %p: ReConfigure_Cfm", sep);
+ DBG("Source %p: ReConfigure_Cfm", sep);
setup = find_setup_by_session(session);
if (!setup)
return;
- if (setup->canceled) {
- if (!err)
- avdtp_close(session, stream);
- setup_unref(setup);
- return;
- }
-
if (err) {
setup->stream = NULL;
setup->err = err;
@@ -906,6 +929,18 @@
finalize_config(setup);
}
+static void delay_report_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ DBG("Sink %p: DelayReport_Cfm", sep);
+ else
+ DBG("Source %p: DelayReport_Cfm", sep);
+}
+
static struct avdtp_sep_cfm cfm = {
.set_configuration = setconf_cfm,
.get_configuration = getconf_cfm,
@@ -914,7 +949,8 @@
.suspend = suspend_cfm,
.close = close_cfm,
.abort = abort_cfm,
- .reconfigure = reconf_cfm
+ .reconfigure = reconf_cfm,
+ .delay_report = delay_report_cfm,
};
static struct avdtp_sep_ind sbc_ind = {
@@ -926,7 +962,8 @@
.suspend = suspend_ind,
.close = close_ind,
.abort = abort_ind,
- .reconfigure = reconf_ind
+ .reconfigure = reconf_ind,
+ .delayreport = delayreport_ind,
};
static struct avdtp_sep_ind mpeg_ind = {
@@ -938,10 +975,11 @@
.suspend = suspend_ind,
.close = close_ind,
.abort = abort_ind,
- .reconfigure = reconf_ind
+ .reconfigure = reconf_ind,
+ .delayreport = delayreport_ind,
};
-static sdp_record_t *a2dp_record(uint8_t type)
+static sdp_record_t *a2dp_record(uint8_t type, uint16_t avdtp_ver)
{
sdp_list_t *svclass_id, *pfseq, *apseq, *root;
uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid;
@@ -949,7 +987,8 @@
sdp_list_t *aproto, *proto[2];
sdp_record_t *record;
sdp_data_t *psm, *version, *features;
- uint16_t lp = AVDTP_UUID, ver = 0x0100, feat = 0x000F;
+ uint16_t lp = AVDTP_UUID;
+ uint16_t a2dp_ver = 0x0102, feat = 0x000f;
record = sdp_record_alloc();
if (!record)
@@ -967,7 +1006,7 @@
sdp_set_service_classes(record, svclass_id);
sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
- profile[0].version = 0x0100;
+ profile[0].version = a2dp_ver;
pfseq = sdp_list_append(0, &profile[0]);
sdp_set_profile_descs(record, pfseq);
@@ -979,7 +1018,7 @@
sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID);
proto[1] = sdp_list_append(0, &avdtp_uuid);
- version = sdp_data_alloc(SDP_UINT16, &ver);
+ version = sdp_data_alloc(SDP_UINT16, &avdtp_ver);
proto[1] = sdp_list_append(proto[1], version);
apseq = sdp_list_append(apseq, proto[1]);
@@ -1008,7 +1047,7 @@
}
static struct a2dp_sep *a2dp_add_sep(struct a2dp_server *server, uint8_t type,
- uint8_t codec)
+ uint8_t codec, gboolean delay_reporting)
{
struct a2dp_sep *sep;
GSList **l;
@@ -1020,8 +1059,8 @@
ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
sep->sep = avdtp_register_sep(&server->src, type,
- AVDTP_MEDIA_TYPE_AUDIO, codec, ind,
- &cfm, sep);
+ AVDTP_MEDIA_TYPE_AUDIO, codec,
+ delay_reporting, ind, &cfm, sep);
if (sep->sep == NULL) {
g_free(sep);
return NULL;
@@ -1029,6 +1068,7 @@
sep->codec = codec;
sep->type = type;
+ sep->delay_reporting = delay_reporting;
if (type == AVDTP_SEP_TYPE_SOURCE) {
l = &server->sources;
@@ -1041,7 +1081,7 @@
if (*record_id != 0)
goto add;
- record = a2dp_record(type);
+ record = a2dp_record(type, server->version);
if (!record) {
error("Unable to allocate new service record");
avdtp_unregister_sep(sep->sep);
@@ -1082,7 +1122,7 @@
{
int sbc_srcs = 1, sbc_sinks = 1;
int mpeg12_srcs = 0, mpeg12_sinks = 0;
- gboolean source = TRUE, sink = FALSE;
+ gboolean source = TRUE, sink = FALSE, delay_reporting;
char *str;
GError *err = NULL;
int i;
@@ -1094,7 +1134,7 @@
str = g_key_file_get_string(config, "General", "Enable", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
if (strstr(str, "Sink"))
@@ -1107,7 +1147,7 @@
str = g_key_file_get_string(config, "General", "Disable", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
if (strstr(str, "Sink"))
@@ -1119,7 +1159,7 @@
str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
sbc_srcs = atoi(str);
@@ -1128,7 +1168,7 @@
str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
mpeg12_srcs = atoi(str);
@@ -1137,7 +1177,7 @@
str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
sbc_sinks = atoi(str);
@@ -1146,7 +1186,7 @@
str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
mpeg12_sinks = atoi(str);
@@ -1165,32 +1205,41 @@
if (!server)
return -ENOMEM;
- av_err = avdtp_init(src, config);
- if (av_err < 0)
+ 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);
}
+ delay_reporting = g_key_file_get_boolean(config, "A2DP",
+ "DelayReporting", NULL);
+ if (delay_reporting)
+ server->version = 0x0103;
+ else
+ server->version = 0x0102;
+
if (source) {
for (i = 0; i < sbc_srcs; i++)
a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,
- A2DP_CODEC_SBC);
+ A2DP_CODEC_SBC, delay_reporting);
for (i = 0; i < mpeg12_srcs; i++)
a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,
- A2DP_CODEC_MPEG12);
+ A2DP_CODEC_MPEG12, delay_reporting);
}
if (sink) {
for (i = 0; i < sbc_sinks; i++)
a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,
- A2DP_CODEC_SBC);
+ A2DP_CODEC_SBC, delay_reporting);
for (i = 0; i < mpeg12_sinks; i++)
a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,
- A2DP_CODEC_MPEG12);
+ A2DP_CODEC_MPEG12, delay_reporting);
}
return 0;
@@ -1310,7 +1359,7 @@
if (sep->codec != codec_cap->media_codec_type)
return 0;
- debug("a2dp_config: selected SEP %p", sep->sep);
+ DBG("a2dp_config: selected SEP %p", sep->sep);
cb_data = g_new0(struct a2dp_setup_cb, 1);
cb_data->config_cb = cb;
@@ -1349,7 +1398,7 @@
if (l != NULL) {
setup->reconfigure = TRUE;
- if (avdtp_close(session, tmp->stream) < 0) {
+ if (avdtp_close(session, tmp->stream, FALSE) < 0) {
error("avdtp_close failed");
goto failed;
}
@@ -1375,11 +1424,11 @@
case AVDTP_STATE_OPEN:
case AVDTP_STATE_STREAMING:
if (avdtp_stream_has_capabilities(setup->stream, caps)) {
- debug("Configuration match: resuming");
+ DBG("Configuration match: resuming");
g_idle_add((GSourceFunc) finalize_config, setup);
} else if (!setup->reconfigure) {
setup->reconfigure = TRUE;
- if (avdtp_close(session, sep->stream) < 0) {
+ if (avdtp_close(session, sep->stream, FALSE) < 0) {
error("avdtp_close failed");
goto failed;
}
@@ -1514,7 +1563,7 @@
struct a2dp_setup *setup;
GSList *l;
- debug("a2dp_cancel()");
+ DBG("a2dp_cancel()");
setup = find_setup_by_dev(dev);
if (!setup)
@@ -1535,10 +1584,10 @@
setup->cb = g_slist_remove(setup->cb, cb_data);
g_free(cb_data);
- if (!setup->cb) {
- setup->canceled = TRUE;
- setup->sep = NULL;
- }
+ if (setup->cb)
+ return TRUE;
+
+ avdtp_abort(setup->session, setup->stream);
return TRUE;
}
@@ -1548,7 +1597,7 @@
if (sep->locked)
return FALSE;
- debug("SEP %p locked", sep->sep);
+ DBG("SEP %p locked", sep->sep);
sep->locked = TRUE;
return TRUE;
@@ -1562,7 +1611,7 @@
sep->locked = FALSE;
- debug("SEP %p unlocked", sep->sep);
+ DBG("SEP %p unlocked", sep->sep);
if (!sep->stream || state == AVDTP_STATE_IDLE)
return TRUE;
diff --git a/audio/a2dp.h b/audio/a2dp.h
index f08c643..fa81776 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/audio/avdtp.c b/audio/avdtp.c
index 939db10..cf07f6c 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -26,6 +26,7 @@
#include <config.h>
#endif
+#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
@@ -36,12 +37,14 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include <glib.h>
#include <dbus/dbus.h>
-#include "logging.h"
+#include "log.h"
+#include "../src/manager.h"
#include "../src/adapter.h"
#include "../src/device.h"
@@ -71,6 +74,8 @@
#define AVDTP_SUSPEND 0x09
#define AVDTP_ABORT 0x0A
#define AVDTP_SECURITY_CONTROL 0x0B
+#define AVDTP_GET_ALL_CAPABILITIES 0x0C
+#define AVDTP_DELAY_REPORT 0x0D
#define AVDTP_PKT_TYPE_SINGLE 0x00
#define AVDTP_PKT_TYPE_START 0x01
@@ -78,10 +83,12 @@
#define AVDTP_PKT_TYPE_END 0x03
#define AVDTP_MSG_TYPE_COMMAND 0x00
+#define AVDTP_MSG_TYPE_GEN_REJECT 0x01
#define AVDTP_MSG_TYPE_ACCEPT 0x02
#define AVDTP_MSG_TYPE_REJECT 0x03
#define REQ_TIMEOUT 4
+#define ABORT_TIMEOUT 2
#define DISCONNECT_TIMEOUT 1
#define STREAM_TIMEOUT 20
@@ -240,6 +247,12 @@
uint8_t caps[0];
} __attribute__ ((packed));
+struct delay_req {
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+ uint16_t delay;
+} __attribute__ ((packed));
+
#elif __BYTE_ORDER == __BIG_ENDIAN
struct seid_req {
@@ -272,6 +285,12 @@
uint8_t caps[0];
} __attribute__ ((packed));
+struct delay_req {
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+ uint16_t delay;
+} __attribute__ ((packed));
+
#else
#error "Unknown byte order"
#endif
@@ -300,12 +319,14 @@
uint8_t type;
uint8_t media_type;
struct avdtp_service_capability *codec;
+ gboolean delay_reporting;
GSList *caps; /* of type struct avdtp_service_capability */
struct avdtp_stream *stream;
};
struct avdtp_server {
bdaddr_t src;
+ uint16_t version;
GIOChannel *io;
GSList *seps;
GSList *sessions;
@@ -316,6 +337,7 @@
struct avdtp_stream *stream;
struct seid_info info;
uint8_t codec;
+ gboolean delay_reporting;
GSList *caps;
struct avdtp_sep_ind *ind;
struct avdtp_sep_cfm *cfm;
@@ -352,6 +374,8 @@
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;
+ gboolean delay_reporting;
+ uint16_t delay; /* AVDTP 1.3 Delay Reporting feature */
};
/* Structure describing an AVDTP connection between two devices */
@@ -360,6 +384,8 @@
int ref;
int free_lock;
+ uint16_t version;
+
struct avdtp_server *server;
bdaddr_t dst;
@@ -422,6 +448,7 @@
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)
{
@@ -514,8 +541,7 @@
cont_fragments = (len - (session->omtu - sizeof(start))) /
(session->omtu - sizeof(cont)) + 1;
- debug("avdtp_send: %zu bytes split into %d fragments", len,
- cont_fragments + 1);
+ DBG("%zu bytes split into %d fragments", len, cont_fragments + 1);
/* Send the start packet */
memset(&start, 0, sizeof(start));
@@ -532,8 +558,7 @@
if (!try_send(sock, session->buf, session->omtu))
return FALSE;
- debug("avdtp_send: first packet with %zu bytes sent",
- session->omtu - sizeof(start));
+ DBG("first packet with %zu bytes sent", session->omtu - sizeof(start));
sent = session->omtu - sizeof(start);
@@ -545,13 +570,11 @@
if (left + sizeof(cont) > session->omtu) {
cont.packet_type = AVDTP_PKT_TYPE_CONTINUE;
to_copy = session->omtu - sizeof(cont);
- debug("avdtp_send: sending continue with %d bytes",
- to_copy);
+ DBG("sending continue with %d bytes", to_copy);
} else {
cont.packet_type = AVDTP_PKT_TYPE_END;
to_copy = left;
- debug("avdtp_send: sending end with %d bytes",
- to_copy);
+ DBG("sending end with %d bytes", to_copy);
}
cont.transaction = transaction;
@@ -598,7 +621,7 @@
{
struct avdtp_stream *stream = user_data;
- debug("Timed out waiting for peer to close the transport channel");
+ DBG("Timed out waiting for peer to close the transport channel");
stream->timer = 0;
@@ -611,7 +634,7 @@
{
struct avdtp_stream *stream = user_data;
- debug("Timed out waiting for peer to open the transport channel");
+ DBG("Timed out waiting for peer to open the transport channel");
stream->timer = 0;
@@ -777,7 +800,8 @@
struct avdtp_stream *stream = user_data;
struct avdtp *session = stream->session;
- avdtp_close(session, stream);
+ if (avdtp_close(session, stream, FALSE) < 0)
+ error("stream_timeout: closing AVDTP stream failed");
stream->idle_timer = 0;
@@ -872,6 +896,68 @@
}
}
+static void handle_unanswered_req(struct avdtp *session,
+ struct avdtp_stream *stream)
+{
+ struct pending_req *req;
+ struct avdtp_local_sep *lsep;
+ struct avdtp_error err;
+
+ if (session->req->signal_id == AVDTP_ABORT) {
+ /* Avoid freeing the Abort request here */
+ DBG("handle_unanswered_req: Abort req, returning");
+ session->req->stream = NULL;
+ return;
+ }
+
+ req = session->req;
+ session->req = NULL;
+
+ avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);
+
+ lsep = stream->lsep;
+
+ switch (req->signal_id) {
+ case AVDTP_RECONFIGURE:
+ error("No reply to Reconfigure request");
+ if (lsep && lsep->cfm && lsep->cfm->reconfigure)
+ lsep->cfm->reconfigure(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_OPEN:
+ error("No reply to Open request");
+ if (lsep && lsep->cfm && lsep->cfm->open)
+ lsep->cfm->open(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_START:
+ error("No reply to Start request");
+ if (lsep && lsep->cfm && lsep->cfm->start)
+ lsep->cfm->start(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_SUSPEND:
+ error("No reply to Suspend request");
+ if (lsep && lsep->cfm && lsep->cfm->suspend)
+ lsep->cfm->suspend(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_CLOSE:
+ error("No reply to Close request");
+ if (lsep && lsep->cfm && lsep->cfm->close)
+ lsep->cfm->close(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_SET_CONFIGURATION:
+ error("No reply to SetConfiguration request");
+ if (lsep && lsep->cfm && lsep->cfm->set_configuration)
+ lsep->cfm->set_configuration(session, lsep, stream,
+ &err, lsep->user_data);
+ }
+
+ pending_req_free(req);
+}
+
static void avdtp_sep_set_state(struct avdtp *session,
struct avdtp_local_sep *sep,
avdtp_state_t state)
@@ -888,11 +974,11 @@
if (sep->state == state) {
avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);
- debug("stream state change failed: %s", avdtp_strerror(&err));
+ DBG("stream state change failed: %s", avdtp_strerror(&err));
err_ptr = &err;
} else {
err_ptr = NULL;
- debug("stream state changed: %s -> %s",
+ DBG("stream state changed: %s -> %s",
avdtp_statestr(sep->state),
avdtp_statestr(state));
}
@@ -906,6 +992,10 @@
}
switch (state) {
+ case AVDTP_STATE_CONFIGURED:
+ if (sep->info.type == AVDTP_SEP_TYPE_SINK)
+ avdtp_delay_report(session, stream, stream->delay);
+ break;
case AVDTP_STATE_OPEN:
if (old_state > AVDTP_STATE_OPEN && session->auto_dc)
stream->idle_timer = g_timeout_add_seconds(STREAM_TIMEOUT,
@@ -929,7 +1019,7 @@
if (session->pending_open == stream)
handle_transport_connect(session, NULL, 0, 0);
if (session->req && session->req->stream == stream)
- session->req->stream = NULL;
+ handle_unanswered_req(session, stream);
/* Remove pending commands for this stream from the queue */
cleanup_queue(session, stream);
stream_free(stream);
@@ -973,12 +1063,16 @@
static void connection_lost(struct avdtp *session, int err)
{
char address[18];
+ struct audio_device *dev;
ba2str(&session->dst, address);
- debug("Disconnected from %s", address);
+ DBG("Disconnected from %s", address);
- if (session->state == AVDTP_SESSION_STATE_CONNECTING && err != EACCES)
- btd_cancel_authorization(&session->server->src, &session->dst);
+ dev = manager_get_device(&session->server->src, &session->dst, FALSE);
+
+ if (dev != NULL && session->state == AVDTP_SESSION_STATE_CONNECTING &&
+ err != EACCES)
+ audio_device_cancel_authorization(dev, auth_cb, session);
session->free_lock = 1;
@@ -1022,13 +1116,16 @@
session->ref--;
- debug("avdtp_unref(%p): ref=%d", session, session->ref);
+ DBG("%p: ref=%d", session, session->ref);
if (session->ref == 1) {
if (session->state == AVDTP_SESSION_STATE_CONNECTING &&
session->io) {
- btd_cancel_authorization(&session->server->src,
- &session->dst);
+ struct audio_device *dev;
+ dev = manager_get_device(&session->server->src,
+ &session->dst, FALSE);
+ audio_device_cancel_authorization(dev, auth_cb,
+ session);
g_io_channel_shutdown(session->io, TRUE, NULL);
g_io_channel_unref(session->io);
session->io = NULL;
@@ -1046,8 +1143,7 @@
server = session->server;
- debug("avdtp_unref(%p): freeing session and removing from list",
- session);
+ DBG("%p: freeing session and removing from list", session);
if (session->dc_timer)
remove_disconnect_timer(session);
@@ -1068,7 +1164,7 @@
struct avdtp *avdtp_ref(struct avdtp *session)
{
session->ref++;
- debug("avdtp_ref(%p): ref=%d", session, session->ref);
+ DBG("%p: ref=%d", session, session->ref);
if (session->dc_timer)
remove_disconnect_timer(session);
return session;
@@ -1112,12 +1208,16 @@
}
static GSList *caps_to_list(uint8_t *data, int size,
- struct avdtp_service_capability **codec)
+ struct avdtp_service_capability **codec,
+ gboolean *delay_reporting)
{
GSList *caps;
int processed;
- for (processed = 0, caps = NULL; processed + 2 < size;) {
+ if (delay_reporting)
+ *delay_reporting = FALSE;
+
+ for (processed = 0, caps = NULL; processed + 2 <= size;) {
struct avdtp_service_capability *cap;
uint8_t length, category;
@@ -1142,16 +1242,18 @@
length >=
sizeof(struct avdtp_media_codec_capability))
*codec = cap;
+ else if (category == AVDTP_DELAY_REPORTING && delay_reporting)
+ *delay_reporting = TRUE;
}
return caps;
}
static gboolean avdtp_unknown_cmd(struct avdtp *session, uint8_t transaction,
- void *buf, int size)
+ uint8_t signal_id)
{
- return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
- 0, NULL, 0);
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_GEN_REJECT,
+ signal_id, NULL, 0);
}
static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
@@ -1188,12 +1290,16 @@
}
static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
- struct seid_req *req, unsigned int size)
+ struct seid_req *req, unsigned int size,
+ gboolean get_all)
{
GSList *l, *caps;
struct avdtp_local_sep *sep = NULL;
unsigned int rsp_size;
uint8_t err, buf[1024], *ptr = buf;
+ uint8_t cmd;
+
+ cmd = get_all ? AVDTP_GET_ALL_CAPABILITIES : AVDTP_GET_CAPABILITIES;
if (size < sizeof(struct seid_req)) {
err = AVDTP_BAD_LENGTH;
@@ -1206,8 +1312,11 @@
goto failed;
}
- if (!sep->ind->get_capability(session, sep, &caps, &err,
- sep->user_data))
+ 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;
for (l = caps, rsp_size = 0; l != NULL; l = g_slist_next(l)) {
@@ -1225,12 +1334,12 @@
g_slist_free(caps);
- return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
- AVDTP_GET_CAPABILITIES, buf, rsp_size);
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, cmd,
+ buf, rsp_size);
failed:
- return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
- AVDTP_GET_CAPABILITIES, &err, sizeof(err));
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, cmd,
+ &err, sizeof(err));
}
static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
@@ -1264,6 +1373,7 @@
dev = manager_get_device(&src, &dst, FALSE);
if (!dev) {
error("Unable to get a audio device object");
+ err = AVDTP_BAD_STATE;
goto failed;
}
@@ -1273,6 +1383,7 @@
btd_device_add_uuid(dev->btd_dev, A2DP_SINK_UUID);
if (!dev->sink) {
error("Unable to get a audio sink object");
+ err = AVDTP_BAD_STATE;
goto failed;
}
}
@@ -1288,7 +1399,8 @@
stream->rseid = req->int_seid;
stream->caps = caps_to_list(req->caps,
size - sizeof(struct setconf_req),
- &stream->codec);
+ &stream->codec,
+ &stream->delay_reporting);
/* Verify that the Media Transport capability's length = 0. Reject otherwise */
for (l = stream->caps; l != NULL; l = g_slist_next(l)) {
@@ -1300,6 +1412,9 @@
}
}
+ if (stream->delay_reporting && session->version < 0x0103)
+ session->version = 0x0103;
+
if (sep->ind && sep->ind->set_configuration) {
if (!sep->ind->set_configuration(session, sep, stream,
stream->caps, &err,
@@ -1315,6 +1430,7 @@
}
sep->stream = stream;
+ sep->info.inuse = 1;
session->streams = g_slist_append(session->streams, stream);
avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
@@ -1379,7 +1495,7 @@
static gboolean avdtp_reconf_cmd(struct avdtp *session, uint8_t transaction,
struct seid_req *req, int size)
{
- return avdtp_unknown_cmd(session, transaction, (void *) req, size);
+ return avdtp_unknown_cmd(session, transaction, AVDTP_RECONFIGURE);
}
static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
@@ -1630,7 +1746,52 @@
static gboolean avdtp_secctl_cmd(struct avdtp *session, uint8_t transaction,
struct seid_req *req, int size)
{
- return avdtp_unknown_cmd(session, transaction, (void *) req, size);
+ return avdtp_unknown_cmd(session, transaction, AVDTP_SECURITY_CONTROL);
+}
+
+static gboolean avdtp_delayreport_cmd(struct avdtp *session,
+ uint8_t transaction,
+ struct delay_req *req,
+ unsigned int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ uint8_t err;
+
+ if (size < sizeof(struct delay_req)) {
+ error("Too short delay report request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(session->server, req->acp_seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->state != AVDTP_STATE_CONFIGURED &&
+ sep->state != AVDTP_STATE_STREAMING) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ stream->delay = ntohs(req->delay);
+
+ if (sep->ind && sep->ind->delayreport) {
+ if (!sep->ind->delayreport(session, sep, stream->rseid,
+ stream->delay, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+ AVDTP_DELAY_REPORT, NULL, 0);
+
+failed:
+ return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+ AVDTP_DELAY_REPORT, &err, sizeof(err));
}
static gboolean avdtp_parse_cmd(struct avdtp *session, uint8_t transaction,
@@ -1638,41 +1799,48 @@
{
switch (signal_id) {
case AVDTP_DISCOVER:
- debug("Received DISCOVER_CMD");
+ DBG("Received DISCOVER_CMD");
return avdtp_discover_cmd(session, transaction, buf, size);
case AVDTP_GET_CAPABILITIES:
- debug("Received GET_CAPABILITIES_CMD");
- return avdtp_getcap_cmd(session, transaction, buf, size);
+ DBG("Received GET_CAPABILITIES_CMD");
+ return avdtp_getcap_cmd(session, transaction, buf, size,
+ FALSE);
+ case AVDTP_GET_ALL_CAPABILITIES:
+ DBG("Received GET_ALL_CAPABILITIES_CMD");
+ return avdtp_getcap_cmd(session, transaction, buf, size, TRUE);
case AVDTP_SET_CONFIGURATION:
- debug("Received SET_CONFIGURATION_CMD");
+ DBG("Received SET_CONFIGURATION_CMD");
return avdtp_setconf_cmd(session, transaction, buf, size);
case AVDTP_GET_CONFIGURATION:
- debug("Received GET_CONFIGURATION_CMD");
+ DBG("Received GET_CONFIGURATION_CMD");
return avdtp_getconf_cmd(session, transaction, buf, size);
case AVDTP_RECONFIGURE:
- debug("Received RECONFIGURE_CMD");
+ DBG("Received RECONFIGURE_CMD");
return avdtp_reconf_cmd(session, transaction, buf, size);
case AVDTP_OPEN:
- debug("Received OPEN_CMD");
+ DBG("Received OPEN_CMD");
return avdtp_open_cmd(session, transaction, buf, size);
case AVDTP_START:
- debug("Received START_CMD");
+ DBG("Received START_CMD");
return avdtp_start_cmd(session, transaction, buf, size);
case AVDTP_CLOSE:
- debug("Received CLOSE_CMD");
+ DBG("Received CLOSE_CMD");
return avdtp_close_cmd(session, transaction, buf, size);
case AVDTP_SUSPEND:
- debug("Received SUSPEND_CMD");
+ DBG("Received SUSPEND_CMD");
return avdtp_suspend_cmd(session, transaction, buf, size);
case AVDTP_ABORT:
- debug("Received ABORT_CMD");
+ DBG("Received ABORT_CMD");
return avdtp_abort_cmd(session, transaction, buf, size);
case AVDTP_SECURITY_CONTROL:
- debug("Received SECURITY_CONTROL_CMD");
+ DBG("Received SECURITY_CONTROL_CMD");
return avdtp_secctl_cmd(session, transaction, buf, size);
+ case AVDTP_DELAY_REPORT:
+ DBG("Received DELAY_REPORT_CMD");
+ return avdtp_delayreport_cmd(session, transaction, buf, size);
default:
- debug("Received unknown request id %u", signal_id);
- return avdtp_unknown_cmd(session, transaction, buf, size);
+ DBG("Received unknown request id %u", signal_id);
+ return avdtp_unknown_cmd(session, transaction, signal_id);
}
}
@@ -1791,7 +1959,7 @@
if (session->in.no_of_packets > 1) {
session->in.no_of_packets--;
- debug("Received AVDTP fragment. %d to go",
+ DBG("Received AVDTP fragment. %d to go",
session->in.no_of_packets);
return PARSE_FRAGMENT;
}
@@ -1808,7 +1976,7 @@
struct avdtp_common_header *header;
gsize size;
- debug("session_cb");
+ DBG("");
if (cond & G_IO_NVAL)
return FALSE;
@@ -1895,6 +2063,9 @@
goto failed;
}
break;
+ case AVDTP_MSG_TYPE_GEN_REJECT:
+ error("Received a General Reject message");
+ break;
default:
error("Unknown message type 0x%02X", header->message_type);
break;
@@ -1929,6 +2100,46 @@
return NULL;
}
+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)
+ goto done;
+
+ ba2str(&session->dst, addr);
+ device = adapter_find_device(adapter, addr);
+ if (!device)
+ goto done;
+
+ rec = btd_device_get_record(device, A2DP_SINK_UUID);
+ if (!rec)
+ rec = btd_device_get_record(device, A2DP_SOURCE_UUID);
+
+ if (!rec)
+ goto done;
+
+ if (sdp_get_access_protos(rec, &protos) < 0)
+ goto done;
+
+ proto_desc = sdp_get_proto_desc(protos, AVDTP_UUID);
+ if (proto_desc && proto_desc->dtd == SDP_UINT16)
+ ver = proto_desc->val.uint16;
+
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+
+done:
+ return ver;
+}
+
static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst)
{
struct avdtp_server *server;
@@ -1959,6 +2170,8 @@
session->state = AVDTP_SESSION_STATE_DISCONNECTED;
session->auto_dc = TRUE;
+ session->version = get_version(session);
+
server->sessions = g_slist_append(server->sessions, session);
return session;
@@ -2001,12 +2214,12 @@
}
ba2str(&session->dst, address);
- debug("AVDTP: connected %s channel to %s",
+ DBG("AVDTP: connected %s channel to %s",
session->pending_open ? "transport" : "signaling",
address);
if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
- debug("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu);
+ DBG("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu);
session->buf = g_malloc0(session->imtu);
avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTED);
@@ -2053,8 +2266,6 @@
AVDTP_STATE_IDLE);
} else
connection_lost(session, EIO);
-
- return;
}
static void auth_cb(DBusError *derr, void *user_data)
@@ -2101,7 +2312,7 @@
goto drop;
}
- debug("AVDTP: incoming connect from %s", address);
+ DBG("AVDTP: incoming connect from %s", address);
session = avdtp_get_internal(&src, &dst);
if (!session)
@@ -2114,8 +2325,7 @@
* Abort the device's channel in favor of our own.
*/
if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
- debug("avdtp_confirm_cb: connect already in progress"
- " (XCASE connect:connect)");
+ DBG("connect already in progress (XCASE connect:connect)");
goto drop;
}
@@ -2201,20 +2411,19 @@
return ((struct seid_req *) (req->data))->acp_seid;
}
-static gboolean request_timeout(gpointer user_data)
+static int cancel_request(struct avdtp *session, int err)
{
- struct avdtp *session = user_data;
struct pending_req *req;
struct seid_req sreq;
struct avdtp_local_sep *lsep;
struct avdtp_stream *stream;
uint8_t seid;
- struct avdtp_error err;
+ struct avdtp_error averr;
req = session->req;
session->req = NULL;
- avdtp_error_init(&err, AVDTP_ERROR_ERRNO, ETIMEDOUT);
+ avdtp_error_init(&averr, AVDTP_ERROR_ERRNO, err);
seid = req_get_seid(req);
if (seid)
@@ -2222,59 +2431,60 @@
else
stream = NULL;
- if (stream)
+ if (stream) {
+ stream->abort_int = TRUE;
lsep = stream->lsep;
- else
+ } else
lsep = NULL;
switch (req->signal_id) {
case AVDTP_RECONFIGURE:
- error("Reconfigure request timed out");
+ error("Reconfigure: %s (%d)", strerror(err), err);
if (lsep && lsep->cfm && lsep->cfm->reconfigure)
- lsep->cfm->reconfigure(session, lsep, stream, &err,
+ lsep->cfm->reconfigure(session, lsep, stream, &averr,
lsep->user_data);
break;
case AVDTP_OPEN:
- error("Open request timed out");
+ error("Open: %s (%d)", strerror(err), err);
if (lsep && lsep->cfm && lsep->cfm->open)
- lsep->cfm->open(session, lsep, stream, &err,
+ lsep->cfm->open(session, lsep, stream, &averr,
lsep->user_data);
break;
case AVDTP_START:
- error("Start request timed out");
+ error("Start: %s (%d)", strerror(err), err);
if (lsep && lsep->cfm && lsep->cfm->start)
- lsep->cfm->start(session, lsep, stream, &err,
+ lsep->cfm->start(session, lsep, stream, &averr,
lsep->user_data);
break;
case AVDTP_SUSPEND:
- error("Suspend request timed out");
+ error("Suspend: %s (%d)", strerror(err), err);
if (lsep && lsep->cfm && lsep->cfm->suspend)
- lsep->cfm->suspend(session, lsep, stream, &err,
+ lsep->cfm->suspend(session, lsep, stream, &averr,
lsep->user_data);
break;
case AVDTP_CLOSE:
- error("Close request timed out");
+ error("Close: %s (%d)", strerror(err), err);
if (lsep && lsep->cfm && lsep->cfm->close) {
- lsep->cfm->close(session, lsep, stream, &err,
+ lsep->cfm->close(session, lsep, stream, &averr,
lsep->user_data);
if (stream)
stream->close_int = FALSE;
}
break;
case AVDTP_SET_CONFIGURATION:
- error("SetConfiguration request timed out");
+ error("SetConfiguration: %s (%d)", strerror(err), err);
if (lsep && lsep->cfm && lsep->cfm->set_configuration)
lsep->cfm->set_configuration(session, lsep, stream,
- &err, lsep->user_data);
+ &averr, lsep->user_data);
goto failed;
case AVDTP_DISCOVER:
- error("Discover request timed out");
+ error("Discover: %s (%d)", strerror(err), err);
goto failed;
case AVDTP_GET_CAPABILITIES:
- error("GetCapabilities request timed out");
+ error("GetCapabilities: %s (%d)", strerror(err), err);
goto failed;
case AVDTP_ABORT:
- error("Abort request timed out");
+ error("Abort: %s (%d)", strerror(err), err);
goto failed;
}
@@ -2284,20 +2494,28 @@
memset(&sreq, 0, sizeof(sreq));
sreq.acp_seid = seid;
- if (send_request(session, TRUE, stream, AVDTP_ABORT,
- &sreq, sizeof(sreq)) < 0) {
+ err = send_request(session, TRUE, stream, AVDTP_ABORT, &sreq,
+ sizeof(sreq));
+ if (err < 0) {
error("Unable to send abort request");
goto failed;
}
- stream->abort_int = TRUE;
-
goto done;
failed:
- connection_lost(session, ETIMEDOUT);
+ connection_lost(session, err);
done:
pending_req_free(req);
+ return err;
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+ struct avdtp *session = user_data;
+
+ cancel_request(session, ETIMEDOUT);
+
return FALSE;
}
@@ -2334,7 +2552,8 @@
session->req = req;
- req->timeout = g_timeout_add_seconds(REQ_TIMEOUT,
+ req->timeout = g_timeout_add_seconds(req->signal_id == AVDTP_ABORT ?
+ ABORT_TIMEOUT : REQ_TIMEOUT,
request_timeout,
session);
return 0;
@@ -2351,6 +2570,9 @@
{
struct pending_req *req;
+ if (stream && stream->abort_int && signal_id != AVDTP_ABORT)
+ return -EINVAL;
+
req = g_new0(struct pending_req, 1);
req->signal_id = signal_id;
req->data = g_malloc(size);
@@ -2365,6 +2587,12 @@
struct discover_resp *resp, int size)
{
int sep_count, i;
+ uint8_t getcap_cmd;
+
+ if (session->version >= 0x0103 && session->server->version >= 0x0103)
+ getcap_cmd = AVDTP_GET_ALL_CAPABILITIES;
+ else
+ getcap_cmd = AVDTP_GET_CAPABILITIES;
sep_count = size / sizeof(struct seid_info);
@@ -2374,7 +2602,7 @@
struct seid_req req;
int ret;
- debug("seid %d type %d media %d in use %d",
+ DBG("seid %d type %d media %d in use %d",
resp->seps[i].seid, resp->seps[i].type,
resp->seps[i].media_type, resp->seps[i].inuse);
@@ -2396,9 +2624,8 @@
memset(&req, 0, sizeof(req));
req.acp_seid = sep->seid;
- ret = send_request(session, TRUE, NULL,
- AVDTP_GET_CAPABILITIES,
- &req, sizeof(req));
+ ret = send_request(session, TRUE, NULL, getcap_cmd,
+ &req, sizeof(req));
if (ret < 0) {
finalize_discovery(session, -ret);
break;
@@ -2431,7 +2658,7 @@
sep = find_remote_sep(session->seps, seid);
- debug("seid %d type %d media %d", sep->seid,
+ DBG("seid %d type %d media %d", sep->seid,
sep->type, sep->media_type);
if (sep->caps) {
@@ -2439,10 +2666,11 @@
g_slist_free(sep->caps);
sep->caps = NULL;
sep->codec = NULL;
+ sep->delay_reporting = FALSE;
}
sep->caps = caps_to_list(resp->caps, size - sizeof(struct getcap_resp),
- &sep->codec);
+ &sep->codec, &sep->delay_reporting);
return TRUE;
}
@@ -2545,12 +2773,25 @@
return TRUE;
}
+static gboolean avdtp_delay_report_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ void *data, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (sep->cfm && sep->cfm->delay_report)
+ sep->cfm->delay_report(session, sep, stream, NULL, sep->user_data);
+
+ return TRUE;
+}
+
static gboolean avdtp_parse_resp(struct avdtp *session,
struct avdtp_stream *stream,
uint8_t transaction, uint8_t signal_id,
void *buf, int size)
{
struct pending_req *next;
+ const char *get_all = "";
if (session->prio_queue)
next = session->prio_queue->data;
@@ -2561,13 +2802,16 @@
switch (signal_id) {
case AVDTP_DISCOVER:
- debug("DISCOVER request succeeded");
+ DBG("DISCOVER request succeeded");
return avdtp_discover_resp(session, buf, size);
+ case AVDTP_GET_ALL_CAPABILITIES:
+ get_all = "ALL_";
case AVDTP_GET_CAPABILITIES:
- debug("GET_CAPABILITIES request succeeded");
+ DBG("GET_%sCAPABILITIES request succeeded", get_all);
if (!avdtp_get_capabilities_resp(session, buf, size))
return FALSE;
- if (!(next && next->signal_id == AVDTP_GET_CAPABILITIES))
+ if (!(next && (next->signal_id == AVDTP_GET_CAPABILITIES ||
+ next->signal_id == AVDTP_GET_ALL_CAPABILITIES)))
finalize_discovery(session, 0);
return TRUE;
}
@@ -2575,33 +2819,36 @@
/* The remaining commands require an existing stream so bail out
* here if the stream got unexpectedly disconnected */
if (!stream) {
- debug("AVDTP: stream was closed while waiting for reply");
+ DBG("AVDTP: stream was closed while waiting for reply");
return TRUE;
}
switch (signal_id) {
case AVDTP_SET_CONFIGURATION:
- debug("SET_CONFIGURATION request succeeded");
+ DBG("SET_CONFIGURATION request succeeded");
return avdtp_set_configuration_resp(session, stream,
buf, size);
case AVDTP_RECONFIGURE:
- debug("RECONFIGURE request succeeded");
+ DBG("RECONFIGURE request succeeded");
return avdtp_reconfigure_resp(session, stream, buf, size);
case AVDTP_OPEN:
- debug("OPEN request succeeded");
+ DBG("OPEN request succeeded");
return avdtp_open_resp(session, stream, buf, size);
case AVDTP_SUSPEND:
- debug("SUSPEND request succeeded");
+ DBG("SUSPEND request succeeded");
return avdtp_suspend_resp(session, stream, buf, size);
case AVDTP_START:
- debug("START request succeeded");
+ DBG("START request succeeded");
return avdtp_start_resp(session, stream, buf, size);
case AVDTP_CLOSE:
- debug("CLOSE request succeeded");
+ DBG("CLOSE request succeeded");
return avdtp_close_resp(session, stream, buf, size);
case AVDTP_ABORT:
- debug("ABORT request succeeded");
+ DBG("ABORT request succeeded");
return avdtp_abort_resp(session, stream, buf, size);
+ case AVDTP_DELAY_REPORT:
+ DBG("DELAY_REPORT request succeeded");
+ return avdtp_delay_report_resp(session, stream, buf, size);
}
error("Unknown signal id in accept response: %u", signal_id);
@@ -2671,6 +2918,7 @@
avdtp_strerror(&err), err.err.error_code);
return TRUE;
case AVDTP_GET_CAPABILITIES:
+ case AVDTP_GET_ALL_CAPABILITIES:
if (!seid_rej_to_err(buf, size, &err))
return FALSE;
error("GET_CAPABILITIES request rejected: %s (%d)",
@@ -2740,6 +2988,15 @@
if (sep && sep->cfm && sep->cfm->abort)
sep->cfm->abort(session, sep, stream, &err,
sep->user_data);
+ return FALSE;
+ case AVDTP_DELAY_REPORT:
+ if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+ return FALSE;
+ error("DELAY_REPORT request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->delay_report)
+ sep->cfm->delay_report(session, sep, stream, &err,
+ sep->user_data);
return TRUE;
default:
error("Unknown reject response signal id: %u", signal_id);
@@ -2892,6 +3149,11 @@
return sep->codec;
}
+gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep)
+{
+ return sep->delay_reporting;
+}
+
struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep)
{
return sep->stream;
@@ -2902,7 +3164,7 @@
{
struct avdtp_service_capability *cap;
- if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_MEDIA_CODEC)
+ if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_DELAY_REPORTING)
return NULL;
cap = g_malloc(sizeof(struct avdtp_service_capability) + length);
@@ -2925,7 +3187,7 @@
int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
void *user_data)
{
- int ret;
+ int err;
if (session->discov_cb)
return -EBUSY;
@@ -2937,13 +3199,13 @@
return 0;
}
- ret = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
- if (ret == 0) {
+ err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
+ if (err == 0) {
session->discov_cb = cb;
session->user_data = user_data;
}
- return ret;
+ return err;
}
int avdtp_get_seps(struct avdtp *session, uint8_t acp_type, uint8_t media_type,
@@ -3068,7 +3330,7 @@
struct setconf_req *req;
struct avdtp_stream *new_stream;
unsigned char *ptr;
- int ret, caps_len;
+ int err, caps_len;
struct avdtp_service_capability *cap;
GSList *l;
@@ -3078,14 +3340,17 @@
if (!(lsep && rsep))
return -EINVAL;
- debug("avdtp_set_configuration(%p): int_seid=%u, acp_seid=%u",
- session, lsep->info.seid, rsep->seid);
+ DBG("%p: int_seid=%u, acp_seid=%u", session,
+ lsep->info.seid, rsep->seid);
new_stream = g_new0(struct avdtp_stream, 1);
new_stream->session = session;
new_stream->lsep = lsep;
new_stream->rseid = rsep->seid;
+ if (rsep->delay_reporting && lsep->delay_reporting)
+ new_stream->delay_reporting = TRUE;
+
g_slist_foreach(caps, copy_capabilities, &new_stream->caps);
/* Calculate total size of request */
@@ -3106,10 +3371,10 @@
ptr += cap->length + 2;
}
- ret = send_request(session, FALSE, new_stream,
+ err = send_request(session, FALSE, new_stream,
AVDTP_SET_CONFIGURATION, req,
sizeof(struct setconf_req) + caps_len);
- if (ret < 0)
+ if (err < 0)
stream_free(new_stream);
else {
lsep->info.inuse = 1;
@@ -3122,7 +3387,7 @@
g_free(req);
- return ret;
+ return err;
}
int avdtp_reconfigure(struct avdtp *session, GSList *caps,
@@ -3203,7 +3468,8 @@
&req, sizeof(req));
}
-int avdtp_close(struct avdtp *session, struct avdtp_stream *stream)
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+ gboolean immediate)
{
struct seid_req req;
int ret;
@@ -3219,6 +3485,9 @@
return -EINVAL;
}
+ if (immediate && session->req && stream == session->req->stream)
+ return avdtp_abort(session, stream);
+
memset(&req, 0, sizeof(req));
req.acp_seid = stream->rseid;
@@ -3255,9 +3524,13 @@
if (!g_slist_find(session->streams, stream))
return -EINVAL;
- if (stream->lsep->state <= AVDTP_STATE_OPEN)
+ if (stream->lsep->state == AVDTP_STATE_IDLE ||
+ stream->lsep->state == AVDTP_STATE_ABORTING)
return -EINVAL;
+ if (session->req && stream == session->req->stream)
+ return cancel_request(session, ECANCELED);
+
memset(&req, 0, sizeof(req));
req.acp_seid = stream->rseid;
@@ -3269,9 +3542,36 @@
return ret;
}
+int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
+ uint16_t delay)
+{
+ struct delay_req req;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state != AVDTP_STATE_CONFIGURED &&
+ stream->lsep->state != AVDTP_STATE_STREAMING)
+ return -EINVAL;
+
+ if (!stream->delay_reporting || session->version < 0x0103 ||
+ session->server->version < 0x0103)
+ return -EINVAL;
+
+ stream->delay = delay;
+
+ memset(&req, 0, sizeof(req));
+ req.acp_seid = stream->rseid;
+ req.delay = htons(delay);
+
+ return send_request(session, TRUE, stream, AVDTP_DELAY_REPORT,
+ &req, sizeof(req));
+}
+
struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
uint8_t media_type,
uint8_t codec_type,
+ gboolean delay_reporting,
struct avdtp_sep_ind *ind,
struct avdtp_sep_cfm *cfm,
void *user_data)
@@ -3297,8 +3597,9 @@
sep->cfm = cfm;
sep->user_data = user_data;
sep->server = server;
+ sep->delay_reporting = TRUE;
- debug("SEP %p registered: type:%d codec:%d seid:%d", sep,
+ DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
sep->info.type, sep->codec, sep->info.seid);
server->seps = g_slist_append(server->seps, sep);
@@ -3401,33 +3702,44 @@
bacpy(dst, &session->dst);
}
-int avdtp_init(const bdaddr_t *src, GKeyFile *config)
+int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version)
{
GError *err = NULL;
gboolean tmp, master = TRUE;
struct avdtp_server *server;
+ uint16_t ver = 0x0102;
- if (config) {
- tmp = g_key_file_get_boolean(config, "General",
- "Master", &err);
- if (err) {
- debug("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else
- master = tmp;
+ if (!config)
+ goto proceed;
- tmp = g_key_file_get_boolean(config, "General", "AutoConnect",
- &err);
- if (err)
- g_clear_error(&err);
- else
- auto_connect = 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;
+ tmp = g_key_file_get_boolean(config, "General", "AutoConnect",
+ &err);
+ if (err)
+ g_clear_error(&err);
+ else
+ auto_connect = tmp;
+
+ if (g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL))
+ ver = 0x0103;
+
+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);
if (!server->io) {
g_free(server);
diff --git a/audio/avdtp.h b/audio/avdtp.h
index 81b8f58..3fe682b 100644
--- a/audio/avdtp.h
+++ b/audio/avdtp.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -53,6 +53,7 @@
#define AVDTP_HEADER_COMPRESSION 0x05
#define AVDTP_MULTIPLEXING 0x06
#define AVDTP_MEDIA_CODEC 0x07
+#define AVDTP_DELAY_REPORTING 0x08
/* AVDTP error definitions */
#define AVDTP_BAD_HEADER_FORMAT 0x01
@@ -162,6 +163,9 @@
struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
struct avdtp_error *err, void *user_data);
+ void (*delay_report) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
};
/* Callbacks for indicating when we received a new command. The return value
@@ -169,6 +173,7 @@
struct avdtp_sep_ind {
gboolean (*get_capability) (struct avdtp *session,
struct avdtp_local_sep *sep,
+ gboolean get_all,
GSList **caps, uint8_t *err,
void *user_data);
gboolean (*set_configuration) (struct avdtp *session,
@@ -198,6 +203,10 @@
gboolean (*reconfigure) (struct avdtp *session,
struct avdtp_local_sep *lsep,
uint8_t *err, void *user_data);
+ gboolean (*delayreport) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t rseid, uint16_t delay,
+ uint8_t *err, void *user_data);
};
typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
@@ -222,6 +231,8 @@
struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep);
+gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep);
+
struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep);
int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
@@ -264,12 +275,16 @@
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);
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+ gboolean immediate);
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,
uint8_t media_type,
uint8_t codec_type,
+ gboolean delay_reporting,
struct avdtp_sep_ind *ind,
struct avdtp_sep_cfm *cfm,
void *user_data);
@@ -294,5 +309,5 @@
void avdtp_set_auto_disconnect(struct avdtp *session, gboolean auto_dc);
gboolean avdtp_stream_setup_active(struct avdtp *session);
-int avdtp_init(const bdaddr_t *src, GKeyFile *config);
+int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version);
void avdtp_exit(const bdaddr_t *src);
diff --git a/audio/control.c b/audio/control.c
index e55d1f4..f74bb0a 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -46,7 +46,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "error.h"
#include "uinput.h"
#include "adapter.h"
@@ -102,6 +102,8 @@
#define FORWARD_OP 0x4b
#define BACKWARD_OP 0x4c
+#define QUIRK_NO_RELEASE 1 << 0
+
static DBusConnection *connection = NULL;
static gchar *input_device_name = NULL;
static GSList *servers = NULL;
@@ -178,6 +180,8 @@
uint16_t mtu;
gboolean target;
+
+ uint8_t key_quirks[256];
};
static struct {
@@ -197,6 +201,8 @@
static GSList *avctp_callbacks = NULL;
+static void auth_cb(DBusError *derr, void *user_data);
+
static sdp_record_t *avrcp_ct_record()
{
sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -205,7 +211,8 @@
sdp_list_t *aproto, *proto[2];
sdp_record_t *record;
sdp_data_t *psm, *version, *features;
- uint16_t lp = AVCTP_PSM, ver = 0x0100, feat = 0x000f;
+ uint16_t lp = AVCTP_PSM;
+ uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103, feat = 0x000f;
record = sdp_record_alloc();
if (!record)
@@ -229,7 +236,7 @@
sdp_uuid16_create(&avctp, AVCTP_UUID);
proto[1] = sdp_list_append(0, &avctp);
- version = sdp_data_alloc(SDP_UINT16, &ver);
+ version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
proto[1] = sdp_list_append(proto[1], version);
apseq = sdp_list_append(apseq, proto[1]);
@@ -238,7 +245,7 @@
/* Bluetooth Profile Descriptor List */
sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
- profile[0].version = ver;
+ profile[0].version = avrcp_ver;
pfseq = sdp_list_append(0, &profile[0]);
sdp_set_profile_descs(record, pfseq);
@@ -268,7 +275,8 @@
sdp_list_t *aproto, *proto[2];
sdp_record_t *record;
sdp_data_t *psm, *version, *features;
- uint16_t lp = AVCTP_PSM, ver = 0x0100, feat = 0x000f;
+ uint16_t lp = AVCTP_PSM;
+ uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103, feat = 0x000f;
record = sdp_record_alloc();
if (!record)
@@ -292,7 +300,7 @@
sdp_uuid16_create(&avctp, AVCTP_UUID);
proto[1] = sdp_list_append(0, &avctp);
- version = sdp_data_alloc(SDP_UINT16, &ver);
+ version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
proto[1] = sdp_list_append(proto[1], version);
apseq = sdp_list_append(apseq, proto[1]);
@@ -301,7 +309,7 @@
/* Bluetooth Profile Descriptor List */
sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
- profile[0].version = ver;
+ profile[0].version = avrcp_ver;
pfseq = sdp_list_append(0, &profile[0]);
sdp_set_profile_descs(record, pfseq);
@@ -363,15 +371,33 @@
}
for (i = 0; key_map[i].name != NULL; i++) {
- if ((operands[0] & 0x7F) == key_map[i].avrcp) {
- debug("AVRCP: %s %s", key_map[i].name, status);
- send_key(control->uinput, key_map[i].uinput, pressed);
+ uint8_t key_quirks;
+
+ if ((operands[0] & 0x7F) != key_map[i].avrcp)
+ continue;
+
+ DBG("AVRCP: %s %s", key_map[i].name, status);
+
+ key_quirks = control->key_quirks[key_map[i].avrcp];
+
+ if (key_quirks & QUIRK_NO_RELEASE) {
+ if (!pressed) {
+ DBG("AVRCP: Ignoring release");
+ break;
+ }
+
+ DBG("AVRCP: treating key press as press + release");
+ send_key(control->uinput, key_map[i].uinput, 1);
+ send_key(control->uinput, key_map[i].uinput, 0);
break;
}
+
+ send_key(control->uinput, key_map[i].uinput, pressed);
+ break;
}
if (key_map[i].name == NULL)
- debug("AVRCP: unknown button 0x%02X %s",
+ DBG("AVRCP: unknown button 0x%02X %s",
operands[0] & 0x7F, status);
}
@@ -391,9 +417,18 @@
if (control->io_id) {
g_source_remove(control->io_id);
control->io_id = 0;
+
+ if (control->state == AVCTP_STATE_CONNECTING)
+ audio_device_cancel_authorization(dev, auth_cb,
+ control);
}
if (control->uinput >= 0) {
+ char address[18];
+
+ ba2str(&dev->dst, address);
+ DBG("AVRCP: closing uinput for %s", address);
+
ioctl(control->uinput, UI_DEV_DESTROY);
close(control->uinput);
control->uinput = -1;
@@ -409,6 +444,8 @@
switch (new_state) {
case AVCTP_STATE_DISCONNECTED:
+ DBG("AVCTP Disconnected");
+
avctp_disconnected(control->dev);
if (old_state != AVCTP_STATE_CONNECTED)
@@ -421,10 +458,16 @@
emit_property_changed(dev->conn, dev->path,
AUDIO_CONTROL_INTERFACE, "Connected",
DBUS_TYPE_BOOLEAN, &value);
+
+ 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");
value = TRUE;
g_dbus_emit_signal(control->dev->conn, control->dev->path,
AUDIO_CONTROL_INTERFACE, "Connected",
@@ -455,7 +498,7 @@
struct avrcp_header *avrcp;
int ret, packet_size, operand_count, sock;
- if (!(cond | G_IO_IN))
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
goto failed;
sock = g_io_channel_unix_get_fd(control->io);
@@ -464,7 +507,7 @@
if (ret <= 0)
goto failed;
- debug("Got %d bytes of data for AVCTP session %p", ret, control);
+ DBG("Got %d bytes of data for AVCTP session %p", ret, control);
if ((unsigned int) ret < sizeof(struct avctp_header)) {
error("Too small AVCTP packet");
@@ -475,7 +518,7 @@
avctp = (struct avctp_header *) buf;
- debug("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "
+ 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));
@@ -493,7 +536,7 @@
operands = buf + sizeof(struct avctp_header) + sizeof(struct avrcp_header);
operand_count = ret;
- debug("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
+ DBG("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
"opcode 0x%02X, %d operands",
avctp->cr ? "response" : "command",
avrcp->code, avrcp->subunit_type, avrcp->subunit_id,
@@ -527,7 +570,7 @@
operands[0] = 0x07;
if (operand_count >= 2)
operands[1] = SUBUNIT_PANEL << 3;
- debug("reply to %s", avrcp->opcode == OP_UNITINFO ?
+ DBG("reply to %s", avrcp->opcode == OP_UNITINFO ?
"OP_UNITINFO" : "OP_SUBUNITINFO");
} else {
avctp->cr = AVCTP_RESPONSE;
@@ -538,7 +581,7 @@
return TRUE;
failed:
- debug("AVCTP session %p got disconnected", control);
+ DBG("AVCTP session %p got disconnected", control);
avctp_set_state(control, AVCTP_STATE_DISCONNECTED);
return FALSE;
}
@@ -602,20 +645,29 @@
static void init_uinput(struct control *control)
{
- char address[18], *name;
+ struct audio_device *dev = control->dev;
+ char address[18], name[248 + 1], *uinput_dev_name;
- ba2str(&control->dev->dst, address);
+ device_get_name(dev->btd_dev, name, sizeof(name));
+ if (g_str_equal(name, "Nokia CK-20W")) {
+ control->key_quirks[FORWARD_OP] |= QUIRK_NO_RELEASE;
+ control->key_quirks[BACKWARD_OP] |= QUIRK_NO_RELEASE;
+ control->key_quirks[PLAY_OP] |= QUIRK_NO_RELEASE;
+ control->key_quirks[PAUSE_OP] |= QUIRK_NO_RELEASE;
+ }
+
+ ba2str(&dev->dst, address);
/* Use device name from config file if specified */
- name = input_device_name;
- if (!name)
- name = address;
+ uinput_dev_name = input_device_name;
+ if (!uinput_dev_name)
+ uinput_dev_name = address;
- control->uinput = uinput_create(name);
+ control->uinput = uinput_create(uinput_dev_name);
if (control->uinput < 0)
error("AVRCP: failed to init uinput for %s", address);
else
- debug("AVRCP: uinput initialized for %s", address);
+ DBG("AVRCP: uinput initialized for %s", address);
}
static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
@@ -642,7 +694,7 @@
return;
}
- debug("AVCTP: connected to %s", address);
+ DBG("AVCTP: connected to %s", address);
if (!control->io)
control->io = g_io_channel_ref(chan);
@@ -661,6 +713,11 @@
struct control *control = user_data;
GError *err = NULL;
+ if (control->io_id) {
+ g_source_remove(control->io_id);
+ control->io_id = 0;
+ }
+
if (derr && dbus_error_is_set(derr)) {
error("Access denied: %s", derr->message);
avctp_set_state(control, AVCTP_STATE_DISCONNECTED);
@@ -721,6 +778,8 @@
auth_cb, dev->control) < 0)
goto drop;
+ control->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ control_cb, control);
return;
drop:
@@ -799,7 +858,7 @@
tmp = g_key_file_get_boolean(config, "General",
"Master", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_error_free(err);
} else
master = tmp;
@@ -807,7 +866,7 @@
input_device_name = g_key_file_get_string(config,
"AVRCP", "InputDeviceName", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
input_device_name = NULL;
g_error_free(err);
}
@@ -823,11 +882,13 @@
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;
}
@@ -837,12 +898,14 @@
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 controller service record");
sdp_record_free(record);
+ g_free(server);
return -1;
}
server->ct_record_id = record->handle;
@@ -1070,7 +1133,7 @@
struct audio_device *dev = data;
struct control *control = dev->control;
- debug("Unregistered interface %s on path %s",
+ DBG("Unregistered interface %s on path %s",
AUDIO_CONTROL_INTERFACE, dev->path);
if (control->state != AVCTP_STATE_DISCONNECTED)
@@ -1104,7 +1167,7 @@
dev, path_unregister))
return NULL;
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
AUDIO_CONTROL_INTERFACE, dev->path);
control = g_new0(struct control, 1);
diff --git a/audio/control.h b/audio/control.h
index ad0aca5..49f25c2 100644
--- a/audio/control.h
+++ b/audio/control.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/audio/ctl_bluetooth.c b/audio/ctl_bluetooth.c
index 2e12f65..2981385 100644
--- a/audio/ctl_bluetooth.c
+++ b/audio/ctl_bluetooth.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/device.c b/audio/device.c
index 9662dec..ea54f18 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -43,7 +43,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "../src/adapter.h"
#include "../src/device.h"
@@ -157,7 +157,7 @@
priv->authorized = FALSE;
if (dev->priv->state == new_state) {
- debug("state change attempted from %s to %s",
+ DBG("state change attempted from %s to %s",
state_str, state_str);
return;
}
@@ -345,6 +345,11 @@
device_remove_control_timer(dev);
avrcp_disconnect(dev);
}
+ if (priv->hs_state != HEADSET_STATE_DISCONNECTED &&
+ priv->dc_req) {
+ 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) {
@@ -372,11 +377,14 @@
if (dev->auto_connect) {
if (!dev->headset)
device_set_state(dev, AUDIO_STATE_CONNECTED);
- if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
+ else if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
device_set_headset_timer(dev);
- else if (priv->hs_state == HEADSET_STATE_CONNECTED)
+ 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_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:
@@ -427,12 +435,12 @@
}
if (priv->sink_state == SINK_STATE_DISCONNECTED)
device_set_state(dev, AUDIO_STATE_DISCONNECTED);
- else if (old_state == HEADSET_STATE_CONNECT_IN_PROGRESS &&
+ 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_CONNECT_IN_PROGRESS:
+ case HEADSET_STATE_CONNECTING:
device_remove_headset_timer(dev);
if (priv->sink_state == SINK_STATE_DISCONNECTED)
device_set_state(dev, AUDIO_STATE_CONNECTING);
@@ -447,9 +455,11 @@
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)
+ 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_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:
@@ -517,10 +527,15 @@
priv->dc_req = dbus_message_ref(msg);
- if (priv->hs_state != HEADSET_STATE_DISCONNECTED)
- headset_shutdown(dev);
- else if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
+ 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;
@@ -603,7 +618,7 @@
return NULL;
}
- debug("Registered interface %s on path %s", AUDIO_INTERFACE,
+ DBG("Registered interface %s on path %s", AUDIO_INTERFACE,
dev->path);
if (sink_callback_id == 0)
@@ -626,26 +641,24 @@
{
if (!interface) {
if ((dev->sink || dev->source) &&
- avdtp_is_connected(&dev->src, &dev->dst))
+ 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))
+ } 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))
+ avdtp_is_connected(&dev->src, &dev->dst))
return TRUE;
else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
- headset_is_active(dev))
+ headset_is_active(dev))
return TRUE;
else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->control &&
- control_is_active(dev))
+ control_is_active(dev))
return TRUE;
else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway &&
- gateway_is_connected(dev))
+ gateway_is_connected(dev))
return TRUE;
return FALSE;
@@ -655,9 +668,17 @@
{
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);
@@ -773,7 +794,7 @@
GSList *l, *next;
for (l = priv->auths; l != NULL; l = next) {
- struct service_auth *auth = priv->auths->data;
+ struct service_auth *auth = l->data;
next = g_slist_next(l);
@@ -797,3 +818,10 @@
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
index 061c3da..6ec3938 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -67,6 +67,8 @@
struct control *control;
struct target *target;
+ guint hs_preauth_id;
+
struct dev_priv *priv;
};
@@ -82,6 +84,11 @@
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
index 09a401c..07ebdd4 100644
--- a/audio/gateway.c
+++ b/audio/gateway.c
@@ -2,9 +2,10 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -47,444 +48,103 @@
#include "glib-helper.h"
#include "device.h"
#include "gateway.h"
-#include "logging.h"
+#include "log.h"
#include "error.h"
#include "btio.h"
#include "dbus-common.h"
-#define RFCOMM_BUF_SIZE 256
-/* not-more-then-16 defined by GSM + 1 for NULL + padding */
-#define AG_INDICATOR_DESCR_SIZE 20
-#define AG_CALLER_NUM_SIZE 64 /* size of number + type */
+#ifndef DBUS_TYPE_UNIX_FD
+#define DBUS_TYPE_UNIX_FD -1
+#endif
-/* commands */
-#define AG_FEATURES "AT+BRSF=26\r" /* = 0x7F = All features supported */
-#define AG_INDICATORS_SUPP "AT+CIND=?\r"
-#define AG_INDICATORS_VAL "AT+CIND?\r"
-#define AG_INDICATORS_ENABLE "AT+CMER=3,0,0,1\r"
-#define AG_HOLD_MPTY_SUPP "AT+CHLD=?\r"
-#define AG_CALLER_IDENT_ENABLE "AT+CLIP=1\r"
-#define AG_CARRIER_FORMAT "AT+COPS=3,0\r"
-#define AG_EXTENDED_RESULT_CODE "AT+CMEE=1\r"
-
-#define AG_FEATURE_3WAY 0x1
-#define AG_FEATURE_EXTENDED_RES_CODE 0x100
-/* Hold and multipary AG features.
- * Comments below are copied from hands-free spec for reference */
-/* Releases all held calls or sets User Determined User Busy (UDUB)
- * for a waiting call */
-#define AG_CHLD_0 0x01
-/* Releases all active calls (if any exist) and accepts the other
- * (held or waiting) call */
-#define AG_CHLD_1 0x02
-/* Releases specified active call only <x> */
-#define AG_CHLD_1x 0x04
-/* Places all active calls (if any exist) on hold and accepts the other
- * (held or waiting) call */
-#define AG_CHLD_2 0x08
-/* Request private consultation mode with specified call <x> (Place all
- * calls on hold EXCEPT the call <x>) */
-#define AG_CHLD_2x 0x10
-/* Adds a held call to the conversation */
-#define AG_CHLD_3 0x20
-/* Connects the two calls and disconnects the subscriber from both calls
- * (Explicit Call Transfer). Support for this value and its associated
- * functionality is optional for the HF. */
-#define AG_CHLD_4 0x40
-
-#define OK_RESPONSE "\r\nOK\r\n"
-#define ERROR_RESPONSE "\r\nERROR\r\n"
-
-struct indicator {
- gchar descr[AG_INDICATOR_DESCR_SIZE];
- gint value;
+struct hf_agent {
+ char *name; /* Bus id */
+ char *path; /* D-Bus path */
+ guint watch; /* Disconnect watch */
};
struct gateway {
gateway_state_t state;
GIOChannel *rfcomm;
- guint rfcomm_watch_id;
GIOChannel *sco;
gateway_stream_cb_t sco_start_cb;
void *sco_start_cb_data;
- DBusMessage *connect_message;
- guint ag_features;
- guint hold_multiparty_features;
- GSList *indies;
- gboolean is_dialing;
- gboolean call_active;
-
- int sp_gain;
- int mic_gain;
+ struct hf_agent *agent;
+ DBusMessage *msg;
};
-static gboolean rfcomm_ag_data_cb(GIOChannel *chan, GIOCondition cond,
- struct audio_device *device);
-
int gateway_close(struct audio_device *device);
-static void rfcomm_start_watch(struct audio_device *dev)
+static const char *state2str(gateway_state_t state)
{
- struct gateway *gw = dev->gateway;
-
- gw->rfcomm_watch_id = g_io_add_watch(gw->rfcomm,
- G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) rfcomm_ag_data_cb, dev);
-}
-
-static void rfcomm_stop_watch(struct audio_device *dev)
-{
- struct gateway *gw = dev->gateway;
-
- g_source_remove(gw->rfcomm_watch_id);
-}
-
-static gboolean io_channel_write_all(GIOChannel *io, gchar *data,
- gsize count)
-{
- gsize written = 0;
- GIOStatus status;
-
- while (count > 0) {
- status = g_io_channel_write_chars(io, data, count, &written,
- NULL);
- if (status != G_IO_STATUS_NORMAL)
- return FALSE;
-
- data += written;
- count -= written;
+ 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 "";
}
- return TRUE;
}
-/* it's worth to mention that data and response could be the same pointers */
-static gboolean rfcomm_send_and_read(struct gateway *gw, gchar *data,
- gchar *response, gsize count)
+static void agent_free(struct hf_agent *agent)
{
- GIOChannel *rfcomm = gw->rfcomm;
- gsize read = 0;
- gboolean got_ok = FALSE;
- gboolean got_error = FALSE;
- gchar *resp_buf = response;
- gsize toread = RFCOMM_BUF_SIZE - 1;
- GIOStatus status;
-
- if (!io_channel_write_all(rfcomm, data, count))
- return FALSE;
-
- while (!(got_ok || got_error)) {
- status = g_io_channel_read_chars(rfcomm, resp_buf, toread,
- &read, NULL);
- if (status == G_IO_STATUS_NORMAL)
- resp_buf[read] = '\0';
- else {
- debug("rfcomm_send_and_read(): %m");
- return FALSE;
- }
- got_ok = NULL != strstr(resp_buf, OK_RESPONSE);
- got_error = NULL != strstr(resp_buf, ERROR_RESPONSE);
- resp_buf += read;
- toread -= read;
- }
- return TRUE;
-}
-
-/* get <descr> from the names: (<descr>, (<values>)), (<descr>, (<values>))
- * ... */
-static GSList *parse_indicator_names(gchar *names, GSList *indies)
-{
- gchar *current = names - 1;
- GSList *result = indies;
- gchar *next;
- struct indicator *ind;
-
- while (current != NULL) {
- current += 2;
- next = strstr(current, ",(");
- ind = g_slice_new(struct indicator);
- strncpy(ind->descr, current, 20);
- ind->descr[(intptr_t) next - (intptr_t) current] = '\0';
- result = g_slist_append(result, (gpointer) ind);
- current = strstr(next + 1, ",(");
- }
- return result;
-}
-
-/* get values from <val0>,<val1>,... */
-static GSList *parse_indicator_values(gchar *values, GSList *indies)
-{
- gint val;
- gchar *current = values - 1;
- GSList *runner = indies;
- struct indicator *ind;
-
- while (current != NULL) {
- current += 1;
- sscanf(current, "%d", &val);
- current = strchr(current, ',');
- ind = g_slist_nth_data(runner, 0);
- ind->value = val;
- runner = g_slist_next(runner);
- }
- return indies;
-}
-
-/* get values from <val0>,<val1>,... */
-static guint get_hold_mpty_features(gchar *features)
-{
- guint result = 0;
-
- if (strstr(features, "0"))
- result |= AG_CHLD_0;
-
- if (strstr(features, "1"))
- result |= AG_CHLD_1;
-
- if (strstr(features, "1x"))
- result |= AG_CHLD_1x;
-
- if (strstr(features, "2"))
- result |= AG_CHLD_2;
-
- if (strstr(features, "2x"))
- result |= AG_CHLD_2x;
-
- if (strstr(features, "3"))
- result |= AG_CHLD_3;
-
- if (strstr(features, "4"))
- result |= AG_CHLD_4;
-
- return result;
-}
-
-static gboolean establish_service_level_conn(struct gateway *gw)
-{
- gchar buf[RFCOMM_BUF_SIZE];
- gboolean res;
-
- debug("at the begin of establish_service_level_conn()");
- res = rfcomm_send_and_read(gw, AG_FEATURES, buf,
- sizeof(AG_FEATURES) - 1);
- if (!res || sscanf(buf, "\r\n+BRSF:%d", &gw->ag_features) != 1)
- return FALSE;
-
- debug("features are 0x%X", gw->ag_features);
- res = rfcomm_send_and_read(gw, AG_INDICATORS_SUPP, buf,
- sizeof(AG_INDICATORS_SUPP) - 1);
- if (!res || !strstr(buf, "+CIND:"))
- return FALSE;
-
- gw->indies = parse_indicator_names(strchr(buf, '('), NULL);
-
- res = rfcomm_send_and_read(gw, AG_INDICATORS_VAL, buf,
- sizeof(AG_INDICATORS_VAL) - 1);
- if (!res || !strstr(buf, "+CIND:"))
- return FALSE;
-
- gw->indies = parse_indicator_values(strchr(buf, ':') + 1, gw->indies);
-
- res = rfcomm_send_and_read(gw, AG_INDICATORS_ENABLE, buf,
- sizeof(AG_INDICATORS_ENABLE) - 1);
- if (!res || !strstr(buf, "OK"))
- return FALSE;
-
- if ((gw->ag_features & AG_FEATURE_3WAY) != 0) {
- res = rfcomm_send_and_read(gw, AG_HOLD_MPTY_SUPP, buf,
- sizeof(AG_HOLD_MPTY_SUPP) - 1);
- if (!res || !strstr(buf, "+CHLD:")) {
- g_slice_free1(RFCOMM_BUF_SIZE, buf);
- return FALSE;
- }
- gw->hold_multiparty_features = get_hold_mpty_features(
- strchr(buf, '('));
-
- } else
- gw->hold_multiparty_features = 0;
-
- debug("Service layer connection successfully established!");
- rfcomm_send_and_read(gw, AG_CALLER_IDENT_ENABLE, buf,
- sizeof(AG_CALLER_IDENT_ENABLE) - 1);
- rfcomm_send_and_read(gw, AG_CARRIER_FORMAT, buf,
- sizeof(AG_CARRIER_FORMAT) - 1);
- if ((gw->ag_features & AG_FEATURE_EXTENDED_RES_CODE) != 0)
- rfcomm_send_and_read(gw, AG_EXTENDED_RESULT_CODE, buf,
- sizeof(AG_EXTENDED_RESULT_CODE) - 1);
-
- return TRUE;
-}
-
-static void process_ind_change(struct audio_device *dev, guint index,
- gint value)
-{
- struct gateway *gw = dev->gateway;
- struct indicator *ind = g_slist_nth_data(gw->indies, index - 1);
- gchar *name = ind->descr;
-
- ind->value = value;
-
- debug("at the begin of process_ind_change, name is %s", name);
- if (!strcmp(name, "\"call\"")) {
- if (value > 0) {
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE,
- "CallStarted", DBUS_TYPE_INVALID);
- gw->is_dialing = FALSE;
- gw->call_active = TRUE;
- } else {
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE,
- "CallEnded", DBUS_TYPE_INVALID);
- gw->call_active = FALSE;
- }
-
- } else if (!strcmp(name, "\"callsetup\"")) {
- if (value == 0 && gw->is_dialing) {
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE,
- "CallTerminated",
- DBUS_TYPE_INVALID);
- gw->is_dialing = FALSE;
- } else if (!gw->is_dialing && value > 0)
- gw->is_dialing = TRUE;
-
- } else if (!strcmp(name, "\"callheld\"")) {
- /* FIXME: The following code is based on assumptions only.
- * Has to be tested for interoperability
- * I assume that callheld=2 would be sent when dial from HF
- * failed in case of 3-way call
- * Unfortunately this path is not covered by the HF spec so
- * the code has to be tested for interop
- */
- /* '2' means: all calls held, no active calls */
- if (value == 2) {
- if (gw->is_dialing) {
- g_dbus_emit_signal(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE,
- "CallTerminated",
- DBUS_TYPE_INVALID);
- gw->is_dialing = FALSE;
- }
- }
- } else if (!strcmp(name, "\"service\""))
- emit_property_changed(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE, "RegistrationStatus",
- DBUS_TYPE_UINT16, &value);
- else if (!strcmp(name, "\"signal\""))
- emit_property_changed(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE, "SignalStrength",
- DBUS_TYPE_UINT16, &value);
- else if (!strcmp(name, "\"roam\""))
- emit_property_changed(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE, "RoamingStatus",
- DBUS_TYPE_UINT16, &value);
- else if (!strcmp(name, "\"battchg\""))
- emit_property_changed(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE, "BatteryCharge",
- DBUS_TYPE_UINT16, &value);
-}
-
-static void process_ring(struct audio_device *device, GIOChannel *chan,
- gchar *buf)
-{
- gchar number[AG_CALLER_NUM_SIZE];
- gchar *cli;
- gchar *sep;
- gsize read;
- GIOStatus status;
-
- rfcomm_stop_watch(device);
- status = g_io_channel_read_chars(chan, buf, RFCOMM_BUF_SIZE - 1, &read, NULL);
- if (status != G_IO_STATUS_NORMAL)
+ if (!agent)
return;
- debug("at the begin of process_ring");
- if (strlen(buf) > AG_CALLER_NUM_SIZE + 10)
- error("process_ring(): buf is too long '%s'", buf);
- else if ((cli = strstr(buf, "\r\n+CLIP"))) {
- if (sscanf(cli, "\r\n+CLIP: \"%s", number) == 1) {
- sep = strchr(number, '"');
- sep[0] = '\0';
-
- /* FIXME:signal will be emitted on each RING+CLIP.
- * That's bad */
- cli = number;
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_GATEWAY_INTERFACE, "Ring",
- DBUS_TYPE_STRING, &cli,
- DBUS_TYPE_INVALID);
- device->gateway->is_dialing = TRUE;
- } else
- error("process_ring(): '%s' in place of +CLIP after RING", buf);
-
- }
-
- rfcomm_start_watch(device);
+ g_free(agent->name);
+ g_free(agent->path);
+ g_free(agent);
}
-static gboolean rfcomm_ag_data_cb(GIOChannel *chan, GIOCondition cond,
- struct audio_device *device)
+static void change_state(struct audio_device *dev, gateway_state_t new_state)
{
- gchar buf[RFCOMM_BUF_SIZE];
- struct gateway *gw;
- gsize read;
- /* some space for value */
- gchar indicator[AG_INDICATOR_DESCR_SIZE + 4];
- gint value;
- guint index;
- gchar *sep;
+ struct gateway *gw = dev->gateway;
+ const char *val;
- debug("at the begin of rfcomm_ag_data_cb()");
- if (cond & G_IO_NVAL)
+ if (gw->state == new_state)
+ return;
+
+ val = state2str(new_state);
+ gw->state = new_state;
+
+ emit_property_changed(dev->conn, dev->path,
+ AUDIO_GATEWAY_INTERFACE, "State",
+ DBUS_TYPE_STRING, &val);
+}
+
+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;
+ 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_INVALID);
+
+ if (dbus_connection_send_with_reply(dev->conn, msg, &call, -1) == FALSE)
return FALSE;
- gw = device->gateway;
-
- if (cond & (G_IO_ERR | G_IO_HUP)) {
- debug("connection with remote BT is closed");
- gateway_close(device);
- return FALSE;
- }
-
- if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, NULL)
- != G_IO_STATUS_NORMAL)
- return TRUE;
- buf[read] = '\0';
-
- if (strlen(buf) > AG_INDICATOR_DESCR_SIZE + 14)
- error("rfcomm_ag_data_cb(): buf is too long '%s'", buf);
- else if (sscanf(buf, "\r\n+CIEV:%s\r\n", indicator) == 1) {
- sep = strchr(indicator, ',');
- sep[0] = '\0';
- sep += 1;
- index = atoi(indicator);
- value = atoi(sep);
- process_ind_change(device, index, value);
- } else if (strstr(buf, "RING"))
- process_ring(device, chan, buf);
- else if (sscanf(buf, "\r\n+BVRA:%d\r\n", &value) == 1) {
- if (value == 0)
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_GATEWAY_INTERFACE,
- "VoiceRecognitionActive",
- DBUS_TYPE_INVALID);
- else
- g_dbus_emit_signal(device->conn, device->path,
- AUDIO_GATEWAY_INTERFACE,
- "VoiceRecognitionInactive",
- DBUS_TYPE_INVALID);
- } else if (sscanf(buf, "\r\n+VGS:%d\r\n", &value) == 1) {
- gw->sp_gain = value;
- emit_property_changed(device->conn, device->path,
- AUDIO_GATEWAY_INTERFACE, "SpeakerGain",
- DBUS_TYPE_UINT16, &value);
- } else if (sscanf(buf, "\r\n+VGM:%d\r\n", &value) == 1) {
- gw->mic_gain = value;
- emit_property_changed(device->conn, device->path,
- AUDIO_GATEWAY_INTERFACE, "MicrophoneGain",
- DBUS_TYPE_UINT16, &value);
- } else
- error("rfcomm_ag_data_cb(): read wrong data '%s'", buf);
+ dbus_pending_call_set_notify(call, notify, dev, NULL);
+ dbus_pending_call_unref(call);
return TRUE;
}
@@ -498,10 +158,11 @@
return FALSE;
if (cond & (G_IO_ERR | G_IO_HUP)) {
- debug("sco connection is released");
+ 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;
}
@@ -513,114 +174,129 @@
struct audio_device *dev = (struct audio_device *) user_data;
struct gateway *gw = dev->gateway;
- debug("at the begin of sco_connect_cb() in gateway.c");
+ DBG("at the begin of sco_connect_cb() in gateway.c");
+
+ gw->sco = g_io_channel_ref(chan);
+
+ if (gw->sco_start_cb)
+ gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
if (err) {
error("sco_connect_cb(): %s", err->message);
- /* not sure, but from other point of view,
- * what is the reason to have headset which
- * cannot play audio? */
- if (gw->sco_start_cb)
- gw->sco_start_cb(NULL, gw->sco_start_cb_data);
gateway_close(dev);
return;
}
- gw->sco = g_io_channel_ref(chan);
- if (gw->sco_start_cb)
- gw->sco_start_cb(dev, gw->sco_start_cb_data);
-
- /* why is this here? */
- fcntl(g_io_channel_unix_get_fd(chan), F_SETFL, 0);
g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc) sco_io_cb, dev);
}
+static void newconnection_reply(DBusPendingCall *call, void *data)
+{
+ struct audio_device *dev = data;
+ 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");
+ 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 *conn_mes = gw->connect_message;
- gchar gw_addr[18];
- GIOFlags flags;
+ DBusMessage *reply;
+ int sk, ret;
if (err) {
error("connect(): %s", err->message);
if (gw->sco_start_cb)
- gw->sco_start_cb(NULL, gw->sco_start_cb_data);
- return;
+ gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
+ goto fail;
}
- ba2str(&dev->dst, gw_addr);
- /* Blocking mode should be default, but just in case: */
- flags = g_io_channel_get_flags(chan);
- flags &= ~G_IO_FLAG_NONBLOCK;
- flags &= G_IO_FLAG_MASK;
- g_io_channel_set_flags(chan, flags, NULL);
- g_io_channel_set_encoding(chan, NULL, NULL);
- g_io_channel_set_buffered(chan, FALSE);
- if (!gw->rfcomm)
- gw->rfcomm = g_io_channel_ref(chan);
+ if (!gw->agent) {
+ error("Handsfree Agent not registered");
+ goto fail;
+ }
- if (establish_service_level_conn(dev->gateway)) {
- gboolean value = TRUE;
+ sk = g_io_channel_unix_get_fd(chan);
- debug("%s: Connected to %s", dev->path, gw_addr);
- rfcomm_start_watch(dev);
- if (conn_mes) {
- DBusMessage *reply =
- dbus_message_new_method_return(conn_mes);
- dbus_connection_send(dev->conn, reply, NULL);
- dbus_message_unref(reply);
- dbus_message_unref(conn_mes);
- gw->connect_message = NULL;
- }
+ gw->rfcomm = g_io_channel_ref(chan);
- gw->state = GATEWAY_STATE_CONNECTED;
- emit_property_changed(dev->conn, dev->path,
- AUDIO_GATEWAY_INTERFACE,
- "Connected", DBUS_TYPE_BOOLEAN, &value);
+ ret = agent_sendfd(gw->agent, sk, newconnection_reply, dev);
+
+ if (!gw->msg)
return;
- } else
- error("%s: Failed to establish service layer connection to %s",
- dev->path, gw_addr);
- if (NULL != gw->sco_start_cb)
- gw->sco_start_cb(NULL, gw->sco_start_cb_data);
+ if (ret)
+ reply = dbus_message_new_method_return(gw->msg);
+ else
+ reply = g_dbus_create_error(gw->msg, ERROR_INTERFACE ".Failed",
+ "Can not pass file descriptor");
- gateway_close(dev);
+ g_dbus_send_message(dev->conn, reply);
+
+ return;
+
+fail:
+ if (gw->msg)
+ error_common_reply(dev->conn, gw->msg,
+ ERROR_INTERFACE ".Failed",
+ "Connection attempt failed");
+
+ change_state(dev, GATEWAY_STATE_DISCONNECTED);
}
-static void get_record_cb(sdp_list_t *recs, int perr, gpointer user_data)
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
{
struct audio_device *dev = user_data;
- DBusMessage *msg = dev->gateway->connect_message;
- int ch = -1;
+ struct gateway *gw = dev->gateway;
+ int ch;
sdp_list_t *protos, *classes;
uuid_t uuid;
- gateway_stream_cb_t sco_cb;
GIOChannel *io;
- GError *err = NULL;
+ GError *gerr = NULL;
- if (perr < 0) {
- error("Unable to get service record: %s (%d)", strerror(-perr),
- -perr);
+ 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;
}
@@ -631,6 +307,7 @@
uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) {
sdp_list_free(protos, NULL);
error("Invalid service record or not HFP");
+ err = -EIO;
goto fail;
}
@@ -639,39 +316,42 @@
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, &err,
+ 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_CHANNEL, ch,
BT_IO_OPT_INVALID);
if (!io) {
- error("Unable to connect: %s", err->message);
- if (msg) {
- error_common_reply(dev->conn, msg, ERROR_INTERFACE
- ".ConnectionAttemptFailed",
- err->message);
- msg = NULL;
- }
- g_error_free(err);
+ error("Unable to connect: %s", gerr->message);
gateway_close(dev);
+ goto fail;
}
g_io_channel_unref(io);
+
+ change_state(dev, GATEWAY_STATE_CONNECTING);
return;
fail:
- if (msg)
- error_common_reply(dev->conn, msg, ERROR_INTERFACE
- ".NotSupported", "Not supported");
+ if (gw->msg)
+ error_common_reply(dev->conn, gw->msg,
+ ERROR_INTERFACE ".NotSupported",
+ "Not supported");
- dev->gateway->connect_message = NULL;
+ change_state(dev, GATEWAY_STATE_DISCONNECTED);
- sco_cb = dev->gateway->sco_start_cb;
- if (sco_cb)
- sco_cb(NULL, dev->gateway->sco_start_cb_data);
+ if (!gerr)
+ g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED,
+ "connect: %s (%d)", strerror(-err), -err);
+
+ if (gw->sco_start_cb)
+ gw->sco_start_cb(dev, gerr, gw->sco_start_cb_data);
+
+ g_error_free(gerr);
}
static int get_records(struct audio_device *device)
@@ -689,23 +369,47 @@
struct audio_device *au_dev = (struct audio_device *) data;
struct gateway *gw = au_dev->gateway;
- debug("at the begin of ag_connect()");
- if (gw->rfcomm)
+ if (!gw->agent)
return g_dbus_create_error(msg, ERROR_INTERFACE
- ".AlreadyConnected",
- "Already Connected");
+ ".Failed", "Agent not assigned");
- gw->connect_message = dbus_message_ref(msg);
- if (get_records(au_dev) < 0) {
- dbus_message_unref(gw->connect_message);
+ if (get_records(au_dev) < 0)
return g_dbus_create_error(msg, ERROR_INTERFACE
".ConnectAttemptFailed",
"Connect Attempt Failed");
- }
- debug("at the end of ag_connect()");
+
+ gw->msg = dbus_message_ref(msg);
+
return NULL;
}
+int gateway_close(struct audio_device *device)
+{
+ 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;
+ gw->sco_start_cb = NULL;
+ gw->sco_start_cb_data = NULL;
+ }
+
+ change_state(device, GATEWAY_STATE_DISCONNECTED);
+
+ return 0;
+}
+
static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -714,6 +418,9 @@
DBusMessage *reply = NULL;
char gw_addr[18];
+ if (!device->conn)
+ return NULL;
+
reply = dbus_message_new_method_return(msg);
if (!reply)
return NULL;
@@ -725,248 +432,20 @@
gateway_close(device);
ba2str(&device->dst, gw_addr);
- debug("Disconnected from %s, %s", gw_addr, device->path);
+ DBG("Disconnected from %s, %s", gw_addr, device->path);
return reply;
}
-static DBusMessage *process_ag_reponse(DBusMessage *msg, gchar *response)
+static void agent_exited(DBusConnection *conn, void *data)
{
- DBusMessage *reply;
+ struct gateway *gateway = data;
+ struct hf_agent *agent = gateway->agent;
+ DBG("Agent %s exited", agent->name);
- debug("in process_ag_reponse, response is %s", response);
- if (strstr(response, OK_RESPONSE))
- reply = dbus_message_new_method_return(msg);
- else {
- /* FIXME: some code should be here to processes errors
- * in better fasion */
- debug("AG responded with '%s' to %s method call", response,
- dbus_message_get_member(msg));
- reply = dbus_message_new_error(msg, ERROR_INTERFACE
- ".OperationFailed",
- "Operation failed.See log for details");
- }
- return reply;
-}
-
-static DBusMessage *process_simple(DBusMessage *msg, struct audio_device *dev,
- gchar *data)
-{
- struct gateway *gw = dev->gateway;
- gchar buf[RFCOMM_BUF_SIZE];
-
- rfcomm_stop_watch(dev);
- rfcomm_send_and_read(gw, data, buf, strlen(data));
- rfcomm_start_watch(dev);
- return process_ag_reponse(msg, buf);
-}
-
-#define AG_ANSWER "ATA\r"
-
-static DBusMessage *ag_answer(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *dev = data;
- struct gateway *gw = dev->gateway;
-
- if (!gw->rfcomm)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".NotConnected",
- "Not Connected");
-
- if (gw->call_active)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".CallAlreadyAnswered",
- "Call AlreadyAnswered");
-
- return process_simple(msg, dev, AG_ANSWER);
-}
-
-#define AG_HANGUP "AT+CHUP\r"
-
-static DBusMessage *ag_terminate_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *dev = data;
- struct gateway *gw = dev->gateway;
-
- if (!gw->rfcomm)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".NotConnected",
- "Not Connected");
-
- return process_simple(msg, dev, AG_HANGUP);
-}
-
-/* according to GSM spec */
-#define ALLOWED_NUMBER_SYMBOLS "1234567890*#ABCD"
-#define AG_PLACE_CALL "ATD%s;\r"
-/* dialing from memory is not supported as headset spec doesn't define a way
- * to retreive phone memory entries.
- */
-static DBusMessage *ag_call(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct gateway *gw = device->gateway;
- gchar buf[RFCOMM_BUF_SIZE];
- gchar *number;
- gint atd_len;
- DBusMessage *result;
-
- debug("at the begin of ag_call()");
- if (!gw->rfcomm)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".NotConnected",
- "Not Connected");
-
- dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID);
- if (strlen(number) != strspn(number, ALLOWED_NUMBER_SYMBOLS))
- return dbus_message_new_error(msg,
- ERROR_INTERFACE ".BadNumber",
- "Number contains characters which are not allowed");
-
- atd_len = sprintf(buf, AG_PLACE_CALL, number);
- rfcomm_stop_watch(device);
- rfcomm_send_and_read(gw, buf, buf, atd_len);
- rfcomm_start_watch(device);
-
- result = process_ag_reponse(msg, buf);
- return result;
-}
-
-#define AG_GET_CARRIER "AT+COPS?\r"
-
-static DBusMessage *ag_get_operator(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *dev = (struct audio_device *) data;
- struct gateway *gw = dev->gateway;
- gchar buf[RFCOMM_BUF_SIZE];
- GIOChannel *rfcomm = gw->rfcomm;
- gsize read;
- gchar *result, *sep;
- DBusMessage *reply;
- GIOStatus status;
-
- if (!gw->rfcomm)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".NotConnected",
- "Not Connected");
-
- rfcomm_stop_watch(dev);
- io_channel_write_all(rfcomm, AG_GET_CARRIER, strlen(AG_GET_CARRIER));
-
- status = g_io_channel_read_chars(rfcomm, buf, RFCOMM_BUF_SIZE - 1,
- &read, NULL);
- rfcomm_start_watch(dev);
- if (G_IO_STATUS_NORMAL == status) {
- buf[read] = '\0';
- if (strstr(buf, "+COPS")) {
- if (!strrchr(buf, ','))
- result = "0";
- else {
- result = strchr(buf, '\"') + 1;
- sep = strchr(result, '\"');
- sep[0] = '\0';
- }
-
- reply = dbus_message_new_method_return(msg);
- dbus_message_append_args(reply, DBUS_TYPE_STRING,
- &result, DBUS_TYPE_INVALID);
- } else {
- info("ag_get_operator(): '+COPS' expected but"
- " '%s' received", buf);
- reply = dbus_message_new_error(msg, ERROR_INTERFACE
- ".Failed",
- "Unexpected response from AG");
- }
- } else {
- error("ag_get_operator(): %m");
- reply = dbus_message_new_error(msg, ERROR_INTERFACE
- ".ConnectionFailed",
- "Failed to receive response from AG");
- }
-
- return reply;
-}
-
-#define AG_SEND_DTMF "AT+VTS=%c\r"
-static DBusMessage *ag_send_dtmf(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct gateway *gw = device->gateway;
- gchar buf[RFCOMM_BUF_SIZE];
- gchar *number;
- gint com_len;
- gboolean got_ok = TRUE;
- gint num_len;
- gint i = 0;
-
- if (!gw->rfcomm)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".NotConnected",
- "Not Connected");
-
- dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INVALID);
- if (strlen(number) != strspn(number, ALLOWED_NUMBER_SYMBOLS))
- return dbus_message_new_error(msg,
- ERROR_INTERFACE ".BadNumber",
- "Number contains characters which are not allowed");
-
- num_len = strlen(number);
- rfcomm_stop_watch(device);
- while (i < num_len && got_ok) {
- com_len = sprintf(buf, AG_SEND_DTMF, number[i]);
- rfcomm_send_and_read(gw, buf, buf, com_len);
- got_ok = NULL != strstr(buf, OK_RESPONSE);
- i += 1;
- }
- rfcomm_start_watch(device);
- return process_ag_reponse(msg, buf);
-}
-
-#define AG_GET_SUBSCRIBER_NUMS "AT+CNUM\r"
-#define CNUM_LEN 5 /* length of "+CNUM" string */
-#define MAX_NUMBER_CNT 16
-static DBusMessage *ag_get_subscriber_num(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct audio_device *device = data;
- struct gateway *gw = device->gateway;
- gchar buf[RFCOMM_BUF_SIZE];
- gchar *number, *end;
- DBusMessage *reply = dbus_message_new_method_return(msg);
-
- if (!gw->rfcomm)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".NotConnected",
- "Not Connected");
-
- rfcomm_stop_watch(device);
- rfcomm_send_and_read(gw, AG_GET_SUBSCRIBER_NUMS, buf,
- strlen(AG_GET_SUBSCRIBER_NUMS));
- rfcomm_start_watch(device);
-
- if (strlen(buf) > AG_CALLER_NUM_SIZE + 21)
- error("ag_get_subscriber_num(): buf is too long '%s'", buf);
- else if (strstr(buf, "+CNUM")) {
- number = strchr(buf, ',');
- number++;
- end = strchr(number, ',');
- if (end) {
- *end = '\0';
- dbus_message_append_args(reply, DBUS_TYPE_STRING,
- &number, DBUS_TYPE_INVALID);
- }
- } else
- error("ag_get_subscriber_num(): read wrong data '%s'", buf);
-
- return reply;
+ agent_free(agent);
+ gateway->agent = NULL;
}
static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg,
@@ -977,9 +456,8 @@
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter dict;
- gboolean value;
- guint index = 0;
- struct indicator *ind;
+ const char *value;
+
reply = dbus_message_new_method_return(msg);
if (!reply)
@@ -992,80 +470,131 @@
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
- /* Connected */
- value = gateway_is_connected(device);
- dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
+ value = state2str(gw->state);
+ dict_append_entry(&dict, "State",
+ DBUS_TYPE_STRING, &value);
- if (!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 g_dbus_create_error(msg,
+ ERROR_INTERFACE ".AlreadyExists",
+ "Agent already exists");
+
+ 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 argument");
+
+ 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;
- while ((ind = g_slist_nth_data(gw->indies, index))) {
- if(!strcmp(ind->descr, "\"service\""))
- dict_append_entry(&dict, "RegistrationStatus",
- DBUS_TYPE_UINT16, &ind->value);
- else if (!strcmp(ind->descr, "\"signal\""))
- dict_append_entry(&dict, "SignalStrength",
- DBUS_TYPE_UINT16, &ind->value);
- else if (!strcmp(ind->descr, "\"roam\""))
- dict_append_entry(&dict, "RoamingStatus",
- DBUS_TYPE_UINT16, &ind->value);
- else if (!strcmp(ind->descr, "\"battchg\""))
- dict_append_entry(&dict, "BatteryCharge",
- DBUS_TYPE_UINT16, &ind->value);
- index++;
- }
+ if (strcmp(gw->agent->name, dbus_message_get_sender(msg)) != 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Permission denied");
- /* SpeakerGain */
- dict_append_entry(&dict, "SpeakerGain", DBUS_TYPE_UINT16,
- &device->gateway->sp_gain);
+ 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 argument");
- /* MicrophoneGain */
- dict_append_entry(&dict, "MicrophoneGain", DBUS_TYPE_UINT16,
- &device->gateway->mic_gain);
+ if (strcmp(gw->agent->path, path) != 0)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ "Unknown object path");
+
+ g_dbus_remove_watch(device->conn, gw->agent->watch);
+
+ agent_free(gw->agent);
+ gw->agent = NULL;
+
done:
- dbus_message_iter_close_container(&iter, &dict);
- return reply;
+ return dbus_message_new_method_return(msg);
}
static GDBusMethodTable gateway_methods[] = {
{ "Connect", "", "", ag_connect, G_DBUS_METHOD_FLAG_ASYNC },
- { "Disconnect", "", "", ag_disconnect },
- { "AnswerCall", "", "", ag_answer },
- { "TerminateCall", "", "", ag_terminate_call },
- { "Call", "s", "", ag_call },
- { "GetOperatorName", "", "s", ag_get_operator },
- { "SendDTMF", "s", "", ag_send_dtmf },
- { "GetSubscriberNumber", "", "s", ag_get_subscriber_num },
+ { "Disconnect", "", "", ag_disconnect, G_DBUS_METHOD_FLAG_ASYNC },
{ "GetProperties", "", "a{sv}", ag_get_properties },
+ { "RegisterAgent", "o", "", register_agent },
+ { "UnregisterAgent", "o", "", unregister_agent },
{ NULL, NULL, NULL, NULL }
};
static GDBusSignalTable gateway_signals[] = {
- { "Ring", "s" },
- { "CallTerminated", "" },
- { "CallStarted", "" },
- { "CallEnded", "" },
{ "PropertyChanged", "sv" },
{ NULL, NULL }
};
+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)
{
- struct gateway *gw;
+ if (DBUS_TYPE_UNIX_FD < 0)
+ return NULL;
if (!g_dbus_register_interface(dev->conn, dev->path,
AUDIO_GATEWAY_INTERFACE,
gateway_methods, gateway_signals,
- NULL, dev, NULL))
+ NULL, dev, path_unregister))
return NULL;
- debug("in gateway_init, dev is %p", dev);
- gw = g_new0(struct gateway, 1);
- gw->indies = NULL;
- gw->is_dialing = FALSE;
- gw->call_active = FALSE;
- gw->state = GATEWAY_STATE_DISCONNECTED;
- return gw;
+ return g_new0(struct gateway, 1);
}
@@ -1080,8 +609,7 @@
if (!io)
return -EINVAL;
- g_io_channel_ref(io);
- dev->gateway->rfcomm = io;
+ dev->gateway->rfcomm = g_io_channel_ref(io);
return 0;
}
@@ -1096,49 +624,25 @@
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);
+ (GIOFunc) sco_io_cb, dev);
+
+ change_state(dev, GATEWAY_STATE_PLAYING);
+
return 0;
}
-void gateway_start_service(struct audio_device *device)
+void gateway_start_service(struct audio_device *dev)
{
- rfcomm_connect_cb(device->gateway->rfcomm, NULL, device);
-}
+ struct gateway *gw = dev->gateway;
+ GError *err = NULL;
-static void indicator_slice_free(gpointer mem)
-{
- g_slice_free(struct indicator, mem);
-}
+ if (gw->rfcomm == NULL)
+ return;
-int gateway_close(struct audio_device *device)
-{
- struct gateway *gw = device->gateway;
- GIOChannel *rfcomm = gw->rfcomm;
- GIOChannel *sco = gw->sco;
- gboolean value = FALSE;
-
- g_slist_foreach(gw->indies, (GFunc) indicator_slice_free, NULL);
- g_slist_free(gw->indies);
- if (rfcomm) {
- g_io_channel_shutdown(rfcomm, TRUE, NULL);
- g_io_channel_unref(rfcomm);
- gw->rfcomm = NULL;
+ if (!bt_io_accept(gw->rfcomm, rfcomm_connect_cb, dev, NULL, &err)) {
+ error("bt_io_accept: %s", err->message);
+ g_error_free(err);
}
-
- if (sco) {
- g_io_channel_shutdown(sco, TRUE, NULL);
- g_io_channel_unref(sco);
- gw->sco = NULL;
- gw->sco_start_cb = NULL;
- gw->sco_start_cb_data = NULL;
- }
-
- gw->state = GATEWAY_STATE_DISCONNECTED;
-
- emit_property_changed(device->conn, device->path,
- AUDIO_GATEWAY_INTERFACE,
- "Connected", DBUS_TYPE_BOOLEAN, &value);
- return 0;
}
/* These are functions to be called from unix.c for audio system
@@ -1166,10 +670,8 @@
g_error_free(err);
return FALSE;
}
- } else {
- if (cb)
- cb(dev, user_data);
- }
+ } else if (cb)
+ cb(dev, err, user_data);
return TRUE;
}
@@ -1186,7 +688,7 @@
}
if (sco_cb)
- sco_cb(dev, user_data);
+ sco_cb(dev, NULL, user_data);
return 0;
}
@@ -1220,4 +722,3 @@
gw->sco_start_cb = NULL;
gw->sco_start_cb_data = NULL;
}
-
diff --git a/audio/gateway.h b/audio/gateway.h
index e539469..a45ef82 100644
--- a/audio/gateway.h
+++ b/audio/gateway.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -22,20 +22,24 @@
*
*/
-#define AUDIO_GATEWAY_INTERFACE "org.bluez.HeadsetGateway"
+#define AUDIO_GATEWAY_INTERFACE "org.bluez.HandsfreeGateway"
-#define DEFAULT_HSP_HS_CHANNEL 6
#define DEFAULT_HFP_HS_CHANNEL 7
typedef enum {
GATEWAY_STATE_DISCONNECTED,
- GATEWAY_STATE_CONNECTED
+ GATEWAY_STATE_CONNECTING,
+ GATEWAY_STATE_CONNECTED,
+ GATEWAY_STATE_PLAYING,
} gateway_state_t;
-typedef void (*gateway_stream_cb_t) (struct audio_device *dev, void *user_data);
+typedef void (*gateway_stream_cb_t) (struct audio_device *dev, GError *err,
+ void *user_data);
+
+void gateway_unregister(struct audio_device *dev);
struct gateway *gateway_init(struct audio_device *device);
gboolean gateway_is_connected(struct audio_device *dev);
-int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *chan);
+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);
gboolean gateway_request_stream(struct audio_device *dev,
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c
index 0753f38..492fc63 100644
--- a/audio/gsta2dpsink.c
+++ b/audio/gsta2dpsink.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <pthread.h>
+#include "gstpragma.h"
#include "gsta2dpsink.h"
GType gst_avdtp_sink_get_type(void);
@@ -143,8 +144,7 @@
return NULL;
cleanup_and_fail:
- if (element != NULL)
- g_object_unref(G_OBJECT(element));
+ g_object_unref(G_OBJECT(element));
return NULL;
}
diff --git a/audio/gsta2dpsink.h b/audio/gsta2dpsink.h
index 902b678..3ff4e45 100644
--- a/audio/gsta2dpsink.h
+++ b/audio/gsta2dpsink.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/gstavdtpsink.c b/audio/gstavdtpsink.c
index bc25bd1..f0e5b76 100644
--- a/audio/gstavdtpsink.c
+++ b/audio/gstavdtpsink.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
@@ -40,6 +40,7 @@
#include "ipc.h"
#include "rtp.h"
+#include "gstpragma.h"
#include "gstavdtpsink.h"
GST_DEBUG_CATEGORY_STATIC(avdtp_sink_debug);
@@ -1089,6 +1090,7 @@
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,
diff --git a/audio/gstavdtpsink.h b/audio/gstavdtpsink.h
index b4bee39..eb78248 100644
--- a/audio/gstavdtpsink.h
+++ b/audio/gstavdtpsink.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/gstbluetooth.c b/audio/gstbluetooth.c
index 7775b48..9930820 100644
--- a/audio/gstbluetooth.c
+++ b/audio/gstbluetooth.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
@@ -50,21 +50,24 @@
sbc_t sbc;
guint8 *data = gst_type_find_peek(tf, 0, 32);
- if (sbc_init(&sbc, 0) < 0)
+ if (data == NULL)
return;
- if (data == NULL || *data != 0x9c) /* SBC syncword */
+ if (sbc_init(&sbc, 0) < 0)
return;
aux = g_new(guint8, 32);
memcpy(aux, data, 32);
- sbc_parse(&sbc, aux, 32);
- g_free(aux);
- caps = gst_sbc_parse_caps_from_sbc(&sbc);
- sbc_finish(&sbc);
+ if (sbc_parse(&sbc, aux, 32) < 0)
+ goto done;
+ caps = gst_sbc_parse_caps_from_sbc(&sbc);
gst_type_find_suggest(tf, GST_TYPE_FIND_POSSIBLE, caps);
gst_caps_unref(caps);
+
+done:
+ g_free(aux);
+ sbc_finish(&sbc);
}
static gchar *sbc_exts[] = { "sbc", NULL };
diff --git a/audio/gstpragma.h b/audio/gstpragma.h
new file mode 100644
index 0000000..00eb408
--- /dev/null
+++ b/audio/gstpragma.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * 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
+ *
+ */
+
+#pragma GCC diagnostic warning "-Wmissing-declarations"
diff --git a/audio/gstrtpsbcpay.c b/audio/gstrtpsbcpay.c
index 78ffb2a..1159bfe 100644
--- a/audio/gstrtpsbcpay.c
+++ b/audio/gstrtpsbcpay.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
@@ -25,6 +25,7 @@
#include <config.h>
#endif
+#include "gstpragma.h"
#include "gstrtpsbcpay.h"
#include <math.h>
#include <string.h>
diff --git a/audio/gstrtpsbcpay.h b/audio/gstrtpsbcpay.h
index 7b314aa..a444b49 100644
--- a/audio/gstrtpsbcpay.h
+++ b/audio/gstrtpsbcpay.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcdec.c b/audio/gstsbcdec.c
index 4b46f52..2e5cb0a 100644
--- a/audio/gstsbcdec.c
+++ b/audio/gstsbcdec.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
#include <string.h>
+#include "gstpragma.h"
#include "gstsbcutil.h"
#include "gstsbcdec.h"
diff --git a/audio/gstsbcdec.h b/audio/gstsbcdec.h
index 383a3bf..6a15fb0 100644
--- a/audio/gstsbcdec.h
+++ b/audio/gstsbcdec.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c
index 0ecf39c..d2de4ee 100644
--- a/audio/gstsbcenc.c
+++ b/audio/gstsbcenc.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
#include <string.h>
+#include "gstpragma.h"
#include "gstsbcutil.h"
#include "gstsbcenc.h"
diff --git a/audio/gstsbcenc.h b/audio/gstsbcenc.h
index 6d69922..0c8508b 100644
--- a/audio/gstsbcenc.h
+++ b/audio/gstsbcenc.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcparse.c b/audio/gstsbcparse.c
index 30d56ba..a44b52c 100644
--- a/audio/gstsbcparse.c
+++ b/audio/gstsbcparse.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
#include <string.h>
+#include "gstpragma.h"
#include "gstsbcutil.h"
#include "gstsbcparse.h"
diff --git a/audio/gstsbcparse.h b/audio/gstsbcparse.h
index ef3d1d8..d7331ad 100644
--- a/audio/gstsbcparse.h
+++ b/audio/gstsbcparse.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcutil.c b/audio/gstsbcutil.c
index b102da3..63c90c2 100644
--- a/audio/gstsbcutil.c
+++ b/audio/gstsbcutil.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcutil.h b/audio/gstsbcutil.h
index b8f626b..a7f84d5 100644
--- a/audio/gstsbcutil.h
+++ b/audio/gstsbcutil.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/headset.c b/audio/headset.c
index 2c852d1..99d4c7a 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -51,7 +51,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "device.h"
#include "manager.h"
#include "error.h"
@@ -100,7 +100,7 @@
static char *str_state[] = {
"HEADSET_STATE_DISCONNECTED",
- "HEADSET_STATE_CONNECT_IN_PROGRESS",
+ "HEADSET_STATE_CONNECTING",
"HEADSET_STATE_CONNECTED",
"HEADSET_STATE_PLAY_IN_PROGRESS",
"HEADSET_STATE_PLAYING",
@@ -128,6 +128,25 @@
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;
@@ -144,28 +163,14 @@
guint dc_timer;
- char buf[BUF_SIZE];
- int data_start;
- int data_length;
-
gboolean hfp_active;
gboolean search_hfp;
- gboolean cli_active;
- gboolean cme_enabled;
- gboolean cwa_enabled;
- gboolean pending_ring;
- gboolean inband_ring;
- gboolean nrec;
- gboolean nrec_req;
headset_state_t state;
struct pending_connect *pending;
- int sp_gain;
- int mic_gain;
-
- unsigned int hf_features;
headset_lock_t lock;
+ struct headset_slc *slc;
};
struct event {
@@ -193,7 +198,7 @@
{
return error_common_reply(conn, msg,
ERROR_INTERFACE ".ConnectionAttemptFailed",
- err > 0 ? strerror(err) : "Connection attempt failed");
+ err < 0 ? strerror(-err) : "Connection attempt failed");
}
static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb,
@@ -207,7 +212,7 @@
char *str;
if (features == 0) {
- debug("HFP AG features: (none)");
+ DBG("HFP AG features: (none)");
return;
}
@@ -234,7 +239,7 @@
str = g_string_free(gstr, FALSE);
- debug("%s", str);
+ DBG("%s", str);
g_free(str);
}
@@ -245,7 +250,7 @@
char *str;
if (features == 0) {
- debug("HFP HF features: (none)");
+ DBG("HFP HF features: (none)");
return;
}
@@ -268,7 +273,7 @@
str = g_string_free(gstr, FALSE);
- debug("%s", str);
+ DBG("%s", str);
g_free(str);
}
@@ -278,7 +283,7 @@
switch (state) {
case HEADSET_STATE_DISCONNECTED:
return "disconnected";
- case HEADSET_STATE_CONNECT_IN_PROGRESS:
+ case HEADSET_STATE_CONNECTING:
return "connecting";
case HEADSET_STATE_CONNECTED:
case HEADSET_STATE_PLAY_IN_PROGRESS:
@@ -338,14 +343,15 @@
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;
- hs->hf_features = strtoul(&buf[8], NULL, 10);
+ slc->hf_features = strtoul(&buf[8], NULL, 10);
- print_hf_features(hs->hf_features);
+ print_hf_features(slc->hf_features);
err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
if (err < 0)
@@ -429,7 +435,7 @@
{
struct headset *hs = dev->headset;
- if (hs->pending->err)
+ if (hs->pending->err < 0)
cb->cb(NULL, cb->cb_data);
else
cb->cb(dev, cb->cb_data);
@@ -534,10 +540,12 @@
static int cli_cmp(struct headset *hs)
{
+ struct headset_slc *slc = hs->slc;
+
if (!hs->hfp_active)
return -1;
- if (hs->cli_active)
+ if (slc->cli_active)
return 0;
else
return -1;
@@ -560,15 +568,20 @@
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 && p->msg)
- error_connection_attempt_failed(dev->conn, p->msg, p->err);
-
- pending_connect_finalize(dev);
+ if (p != NULL) {
+ p->err = -errno;
+ if (p->msg)
+ error_connection_attempt_failed(dev->conn,
+ p->msg,
+ p->err);
+ pending_connect_finalize(dev);
+ }
if (hs->rfcomm)
headset_set_state(dev, HEADSET_STATE_CONNECTED);
@@ -578,11 +591,11 @@
return;
}
- debug("SCO socket opened for headset %s", dev->path);
+ DBG("SCO socket opened for headset %s", dev->path);
sk = g_io_channel_unix_get_fd(chan);
- debug("SCO fd=%d", sk);
+ DBG("SCO fd=%d", sk);
if (p) {
p->io = NULL;
@@ -599,12 +612,12 @@
headset_set_state(dev, HEADSET_STATE_PLAYING);
- if (hs->pending_ring) {
+ if (slc->pending_ring) {
ring_timer_cb(NULL);
ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
ring_timer_cb,
NULL);
- hs->pending_ring = FALSE;
+ slc->pending_ring = FALSE;
}
}
@@ -657,7 +670,7 @@
struct headset *hs = dev->headset;
struct pending_connect *p = hs->pending;
- debug("HFP Service Level Connection established");
+ DBG("HFP Service Level Connection established");
headset_set_state(dev, HEADSET_STATE_CONNECTED);
@@ -684,9 +697,10 @@
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) {
- if (hs->cme_enabled)
+ if (slc->cme_enabled)
return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
else
return headset_send(hs, "\r\nERROR\r\n");
@@ -699,6 +713,7 @@
{
struct audio_device *device = telephony_device;
struct headset *hs = device->headset;
+ struct headset_slc *slc = hs->slc;
int ret;
if (err != CME_ERROR_NONE)
@@ -708,10 +723,10 @@
if (ret < 0)
return ret;
- if (hs->state != HEADSET_STATE_CONNECT_IN_PROGRESS)
+ if (hs->state != HEADSET_STATE_CONNECTING)
return 0;
- if (hs->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
+ if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
ag.features & AG_FEATURE_THREE_WAY_CALLING)
return 0;
@@ -739,7 +754,7 @@
g_strfreev(tokens);
tokens = NULL;
- debug("Event reporting (CMER): mode=%d, ind=%d",
+ DBG("Event reporting (CMER): mode=%d, ind=%d",
ag.er_mode, ag.er_ind);
switch (ag.er_ind) {
@@ -775,7 +790,7 @@
if (err < 0)
return err;
- if (hs->state != HEADSET_STATE_CONNECT_IN_PROGRESS)
+ if (hs->state != HEADSET_STATE_CONNECTING)
return 0;
hfp_slc_complete(dev);
@@ -865,11 +880,12 @@
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;
- hs->cli_active = buf[8] == '1' ? TRUE : FALSE;
+ slc->cli_active = buf[8] == '1' ? TRUE : FALSE;
return headset_send(hs, "\r\nOK\r\n");
}
@@ -922,7 +938,7 @@
buf_len = strlen(buf);
if (buf[buf_len - 1] != ';') {
- debug("Rejecting non-voice call dial request");
+ DBG("Rejecting non-voice call dial request");
return -EINVAL;
}
@@ -934,39 +950,35 @@
return 0;
}
-static int signal_gain_setting(struct audio_device *device, const char *buf)
+static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
{
struct headset *hs = device->headset;
- const char *property;
- const char *name;
- dbus_uint16_t gain;
-
- if (strlen(buf) < 8) {
- error("Too short string for Gain setting");
- return -EINVAL;
- }
-
- gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
+ struct headset_slc *slc = hs->slc;
+ const char *name, *property;
if (gain > 15) {
- error("Invalid gain value received: %u", gain);
+ error("Invalid gain value: %u", gain);
return -EINVAL;
}
- switch (buf[5]) {
+ switch (type) {
case HEADSET_GAIN_SPEAKER:
- if (hs->sp_gain == gain)
- goto ok;
+ if (slc->sp_gain == gain) {
+ DBG("Ignoring no-change in speaker gain");
+ return 0;
+ }
name = "SpeakerGainChanged";
property = "SpeakerGain";
- hs->sp_gain = gain;
+ slc->sp_gain = gain;
break;
case HEADSET_GAIN_MICROPHONE:
- if (hs->mic_gain == gain)
- goto ok;
+ if (slc->mic_gain == gain) {
+ DBG("Ignoring no-change in microphone gain");
+ return 0;
+ }
name = "MicrophoneGainChanged";
property = "MicrophoneGain";
- hs->mic_gain = gain;
+ slc->mic_gain = gain;
break;
default:
error("Unknown gain setting");
@@ -982,7 +994,26 @@
AUDIO_HEADSET_INTERFACE, property,
DBUS_TYPE_UINT16, &gain);
-ok:
+ 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)
+ return err;
+
return headset_send(hs, "\r\nOK\r\n");
}
@@ -1030,16 +1061,17 @@
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') {
- hs->cme_enabled = TRUE;
- debug("CME errors enabled for headset %p", hs);
+ slc->cme_enabled = TRUE;
+ DBG("CME errors enabled for headset %p", hs);
} else {
- hs->cme_enabled = FALSE;
- debug("CME errors disabled for headset %p", hs);
+ slc->cme_enabled = FALSE;
+ DBG("CME errors disabled for headset %p", hs);
}
return headset_send(hs, "\r\nOK\r\n");
@@ -1048,16 +1080,17 @@
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') {
- hs->cwa_enabled = TRUE;
- debug("Call waiting notification enabled for headset %p", hs);
+ slc->cwa_enabled = TRUE;
+ DBG("Call waiting notification enabled for headset %p", hs);
} else {
- hs->cwa_enabled = FALSE;
- debug("Call waiting notification disabled for headset %p", hs);
+ slc->cwa_enabled = FALSE;
+ DBG("Call waiting notification disabled for headset %p", hs);
}
return headset_send(hs, "\r\nOK\r\n");
@@ -1077,13 +1110,19 @@
{
struct audio_device *device = telephony_device;
struct headset *hs = device->headset;
+ struct headset_slc *slc = hs->slc;
if (err == CME_ERROR_NONE)
- hs->nrec = hs->nrec_req;
+ 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)
@@ -1118,16 +1157,34 @@
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')
- hs->nrec_req = FALSE;
+ slc->nrec_req = FALSE;
else
- hs->nrec_req = TRUE;
+ slc->nrec_req = TRUE;
- telephony_nr_and_ec_req(device, hs->nrec_req);
+ 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;
}
@@ -1152,6 +1209,7 @@
{ "AT+CCWA", call_waiting_notify },
{ "AT+COPS", operator_selection },
{ "AT+NREC", nr_and_ec },
+ { "AT+BVRA", voice_dial },
{ 0 }
};
@@ -1159,7 +1217,7 @@
{
struct event *ev;
- debug("Received %s", buf);
+ DBG("Received %s", buf);
for (ev = event_callbacks; ev->cmd; ev++) {
if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
@@ -1191,6 +1249,7 @@
struct audio_device *device)
{
struct headset *hs;
+ struct headset_slc *slc;
unsigned char buf[BUF_SIZE];
gsize bytes_read = 0;
gsize free_space;
@@ -1199,9 +1258,10 @@
return FALSE;
hs = device->headset;
+ slc = hs->slc;
if (cond & (G_IO_ERR | G_IO_HUP)) {
- debug("ERR or HUP on RFCOMM socket");
+ DBG("ERR or HUP on RFCOMM socket");
goto failed;
}
@@ -1209,7 +1269,8 @@
&bytes_read) != G_IO_ERROR_NONE)
return TRUE;
- free_space = sizeof(hs->buf) - hs->data_start - hs->data_length - 1;
+ free_space = sizeof(slc->buf) - slc->data_start -
+ slc->data_length - 1;
if (free_space < bytes_read) {
/* Very likely that the HS is sending us garbage so
@@ -1218,45 +1279,45 @@
goto failed;
}
- memcpy(&hs->buf[hs->data_start], buf, bytes_read);
- hs->data_length += bytes_read;
+ 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 */
- hs->buf[hs->data_start + hs->data_length] = '\0';
+ slc->buf[slc->data_start + slc->data_length] = '\0';
- while (hs->data_length > 0) {
+ while (slc->data_length > 0) {
char *cr;
int err;
off_t cmd_len;
- cr = strchr(&hs->buf[hs->data_start], '\r');
+ cr = strchr(&slc->buf[slc->data_start], '\r');
if (!cr)
break;
- cmd_len = 1 + (off_t) cr - (off_t) &hs->buf[hs->data_start];
+ cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
*cr = '\0';
if (cmd_len > 1)
- err = handle_event(device, &hs->buf[hs->data_start]);
+ 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",
- &hs->buf[hs->data_start]);
+ &slc->buf[slc->data_start]);
err = headset_send(hs, "\r\nERROR\r\n");
} else if (err < 0)
error("Error handling command %s: %s (%d)",
- &hs->buf[hs->data_start],
+ &slc->buf[slc->data_start],
strerror(-err), -err);
- hs->data_start += cmd_len;
- hs->data_length -= cmd_len;
+ slc->data_start += cmd_len;
+ slc->data_length -= cmd_len;
- if (!hs->data_length)
- hs->data_start = 0;
+ if (!slc->data_length)
+ slc->data_start = 0;
}
return TRUE;
@@ -1312,7 +1373,10 @@
g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
(GIOFunc) rfcomm_io_cb, dev);
- debug("%s: Connected to %s", dev->path, hs_address);
+ DBG("%s: Connected to %s", dev->path, hs_address);
+
+ hs->slc = g_new0(struct headset_slc, 1);
+ hs->slc->nrec = TRUE;
/* In HFP mode wait for Service Level Connection */
if (hs->hfp_active)
@@ -1371,10 +1435,10 @@
if (svc == HANDSFREE_SVCLASS_ID) {
headset->hfp_handle = record->handle;
- debug("Discovered Handsfree service on channel %d", ch);
+ DBG("Discovered Handsfree service on channel %d", ch);
} else {
headset->hsp_handle = record->handle;
- debug("Discovered Headset service on channel %d", ch);
+ DBG("Discovered Headset service on channel %d", ch);
}
return 0;
@@ -1387,6 +1451,7 @@
struct pending_connect *p = hs->pending;
sdp_record_t *record = NULL;
sdp_list_t *r;
+ uuid_t uuid;
assert(hs->pending != NULL);
@@ -1403,9 +1468,11 @@
goto failed_not_supported;
}
+ sdp_uuid16_create(&uuid, p->svclass);
+
for (r = recs; r != NULL; r = r->next) {
sdp_list_t *classes;
- uuid_t uuid;
+ uuid_t class;
record = r->data;
@@ -1414,16 +1481,12 @@
continue;
}
- memcpy(&uuid, classes->data, sizeof(uuid));
+ memcpy(&class, classes->data, sizeof(uuid));
sdp_list_free(classes, free);
- if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16) {
- error("Not a 16 bit UUID");
- continue;
- }
- if (uuid.value.uuid16 == p->svclass)
+ if (sdp_uuid_cmp(&class, &uuid) == 0)
break;
}
@@ -1489,7 +1552,7 @@
return 0;
}
- headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);
+ headset_set_state(device, HEADSET_STATE_CONNECTING);
pending_connect_init(hs, HEADSET_STATE_CONNECTED);
@@ -1521,7 +1584,7 @@
ba2str(&dev->dst, address);
- debug("%s: Connecting to %s channel %d", dev->path, 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,
@@ -1541,7 +1604,7 @@
hs->hfp_active = hs->hfp_handle != 0 ? TRUE : FALSE;
- headset_set_state(dev, HEADSET_STATE_CONNECT_IN_PROGRESS);
+ headset_set_state(dev, HEADSET_STATE_CONNECTING);
pending_connect_init(hs, HEADSET_STATE_CONNECTED);
@@ -1643,10 +1706,10 @@
struct headset *hs = device->headset;
int err;
- if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)
+ if (hs->state == HEADSET_STATE_CONNECTING)
return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",
"Connect in Progress");
- else if (hs->state > HEADSET_STATE_CONNECT_IN_PROGRESS)
+ else if (hs->state > HEADSET_STATE_CONNECTING)
return g_dbus_create_error(msg, ERROR_INTERFACE
".AlreadyConnected",
"Already Connected");
@@ -1691,7 +1754,7 @@
return NULL;
if (ag.ring_timer) {
- debug("IndicateCall received when already indicating");
+ DBG("IndicateCall received when already indicating");
goto done;
}
@@ -1731,7 +1794,7 @@
g_source_remove(ag.ring_timer);
ag.ring_timer = 0;
} else
- debug("Got CancelCall method call but no call is active");
+ DBG("Got CancelCall method call but no call is active");
return reply;
}
@@ -1752,7 +1815,7 @@
switch (hs->state) {
case HEADSET_STATE_DISCONNECTED:
- case HEADSET_STATE_CONNECT_IN_PROGRESS:
+ case HEADSET_STATE_CONNECTING:
return g_dbus_create_error(msg, ERROR_INTERFACE
".NotConnected",
"Device not Connected");
@@ -1789,10 +1852,11 @@
{
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 || hs->sp_gain < 0)
+ if (hs->state < HEADSET_STATE_CONNECTED)
return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
"Operation not Available");
@@ -1800,7 +1864,7 @@
if (!reply)
return NULL;
- gain = (dbus_uint16_t) hs->sp_gain;
+ gain = (dbus_uint16_t) slc->sp_gain;
dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
DBUS_TYPE_INVALID);
@@ -1814,10 +1878,11 @@
{
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 || hs->mic_gain < 0)
+ if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL)
return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
"Operation not Available");
@@ -1825,7 +1890,7 @@
if (!reply)
return NULL;
- gain = (dbus_uint16_t) hs->mic_gain;
+ gain = (dbus_uint16_t) slc->mic_gain;
dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
DBUS_TYPE_INVALID);
@@ -1848,7 +1913,8 @@
".NotConnected",
"Device not Connected");
- if (gain > 15)
+ err = headset_set_gain(device, gain, type);
+ if (err < 0)
return g_dbus_create_error(msg, ERROR_INTERFACE
".InvalidArgument",
"Must be less than or equal to 15");
@@ -1857,31 +1923,13 @@
if (!reply)
return NULL;
- if (hs->state != HEADSET_STATE_PLAYING)
- goto done;
-
- err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);
- if (err < 0) {
- dbus_message_unref(reply);
- return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ 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 g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
"%s", strerror(-err));
- }
-
-done:
- if (type == HEADSET_GAIN_SPEAKER) {
- hs->sp_gain = gain;
- g_dbus_emit_signal(conn, device->path,
- AUDIO_HEADSET_INTERFACE,
- "SpeakerGainChanged",
- DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
- } else {
- hs->mic_gain = gain;
- g_dbus_emit_signal(conn, device->path,
- AUDIO_HEADSET_INTERFACE,
- "MicrophoneGainChanged",
- DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
+ }
}
return reply;
@@ -1953,11 +2001,13 @@
/* SpeakerGain */
dict_append_entry(&dict, "SpeakerGain",
- DBUS_TYPE_UINT16, &device->headset->sp_gain);
+ DBUS_TYPE_UINT16,
+ &device->headset->slc->sp_gain);
/* MicrophoneGain */
dict_append_entry(&dict, "MicrophoneGain",
- DBUS_TYPE_UINT16, &device->headset->mic_gain);
+ DBUS_TYPE_UINT16,
+ &device->headset->slc->mic_gain);
done:
dbus_message_iter_close_container(&iter, &dict);
@@ -2079,7 +2129,7 @@
break;
default:
- debug("Invalid record passed to headset_update");
+ DBG("Invalid record passed to headset_update");
return;
}
}
@@ -2096,10 +2146,8 @@
hs->rfcomm = NULL;
}
- hs->data_start = 0;
- hs->data_length = 0;
-
- hs->nrec = TRUE;
+ g_free(hs->slc);
+ hs->slc = NULL;
return 0;
}
@@ -2130,11 +2178,11 @@
struct headset *hs = dev->headset;
if (hs->state > HEADSET_STATE_DISCONNECTED) {
- debug("Headset unregistered while device was connected!");
+ DBG("Headset unregistered while device was connected!");
headset_shutdown(dev);
}
- debug("Unregistered interface %s on path %s",
+ DBG("Unregistered interface %s on path %s",
AUDIO_HEADSET_INTERFACE, dev->path);
headset_free(dev);
@@ -2154,12 +2202,7 @@
hs = g_new0(struct headset, 1);
hs->rfcomm_ch = -1;
- hs->sp_gain = -1;
- hs->mic_gain = -1;
hs->search_hfp = server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID);
- hs->hfp_active = FALSE;
- hs->cli_active = FALSE;
- hs->nrec = TRUE;
record = btd_device_get_record(dev->btd_dev, uuidstr);
if (!record)
@@ -2175,7 +2218,7 @@
break;
default:
- debug("Invalid record passed to headset_init");
+ DBG("Invalid record passed to headset_init");
g_free(hs);
return NULL;
}
@@ -2189,7 +2232,7 @@
return NULL;
}
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
AUDIO_HEADSET_INTERFACE, dev->path);
return hs;
@@ -2207,7 +2250,7 @@
str = g_key_file_get_string(config, "General", "SCORouting",
&err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
if (strcmp(str, "PCM") == 0)
@@ -2292,7 +2335,7 @@
hs->dc_timer = 0;
}
- if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS ||
+ if (hs->state == HEADSET_STATE_CONNECTING ||
hs->state == HEADSET_STATE_PLAY_IN_PROGRESS)
return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
@@ -2321,7 +2364,7 @@
hs->dc_timer = 0;
}
- if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)
+ if (hs->state == HEADSET_STATE_CONNECTING)
return connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb,
user_data);
@@ -2349,6 +2392,10 @@
struct headset *hs = dev->headset;
unsigned int id;
+ 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;
@@ -2398,18 +2445,19 @@
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 (hs->pending_ring) {
+ if (slc->pending_ring) {
ring_timer_cb(NULL);
ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
ring_timer_cb,
NULL);
- hs->pending_ring = FALSE;
+ slc->pending_ring = FALSE;
}
return 0;
@@ -2428,6 +2476,7 @@
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;
@@ -2450,17 +2499,17 @@
AUDIO_HEADSET_INTERFACE,
"Disconnected",
DBUS_TYPE_INVALID);
- if (hs->state > HEADSET_STATE_CONNECT_IN_PROGRESS)
+ 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);
+ telephony_device_disconnected(dev);
+ }
active_devices = g_slist_remove(active_devices, dev);
device_remove_disconnect_watch(dev->btd_dev, hs->dc_id);
hs->dc_id = 0;
break;
- case HEADSET_STATE_CONNECT_IN_PROGRESS:
+ case HEADSET_STATE_CONNECTING:
emit_property_changed(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE, "State",
DBUS_TYPE_STRING, &state_str);
@@ -2473,9 +2522,9 @@
DBUS_TYPE_STRING, &state_str);
if (hs->state < state) {
if (ag.features & AG_FEATURE_INBAND_RINGTONE)
- hs->inband_ring = TRUE;
+ slc->inband_ring = TRUE;
else
- hs->inband_ring = FALSE;
+ slc->inband_ring = FALSE;
g_dbus_emit_signal(dev->conn, dev->path,
AUDIO_HEADSET_INTERFACE,
"Connected",
@@ -2520,16 +2569,16 @@
AUDIO_HEADSET_INTERFACE, "Playing",
DBUS_TYPE_BOOLEAN, &value);
- if (hs->sp_gain >= 0)
- headset_send(hs, "\r\n+VGS=%u\r\n", hs->sp_gain);
- if (hs->mic_gain >= 0)
- headset_send(hs, "\r\n+VGM=%u\r\n", hs->mic_gain);
+ 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;
- debug("State changed %s: %s -> %s", dev->path, str_state[old_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) {
@@ -2632,7 +2681,10 @@
{
struct headset *hs = dev->headset;
- return hs->nrec;
+ if (!hs->slc)
+ return TRUE;
+
+ return hs->slc->nrec;
}
gboolean headset_get_sco_hci(struct audio_device *dev)
@@ -2657,7 +2709,7 @@
return -ENODEV;
if (!ag.er_ind) {
- debug("telephony_report_event called but events are disabled");
+ DBG("telephony_report_event called but events are disabled");
return -EINVAL;
}
@@ -2689,6 +2741,7 @@
{
struct audio_device *dev;
struct headset *hs;
+ struct headset_slc *slc;
if (!active_devices)
return -ENODEV;
@@ -2696,24 +2749,25 @@
/* Get the latest connected device */
dev = active_devices->data;
hs = dev->headset;
+ slc = hs->slc;
if (ag.ring_timer) {
- debug("telephony_incoming_call_ind: already calling");
+ 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 && hs->inband_ring)
+ if (!hs->hfp_active && slc->inband_ring)
return 0;
g_free(ag.number);
ag.number = g_strdup(number);
ag.number_type = type;
- if (hs->inband_ring && hs->hfp_active &&
+ if (slc->inband_ring && hs->hfp_active &&
hs->state != HEADSET_STATE_PLAYING) {
- hs->pending_ring = TRUE;
+ slc->pending_ring = TRUE;
return 0;
}
@@ -2739,10 +2793,10 @@
/* In case SCO isn't fully up yet */
dev = active_devices->data;
- if (!dev->headset->pending_ring && !ag.ring_timer)
+ if (!dev->headset->slc->pending_ring && !ag.ring_timer)
return -EINVAL;
- dev->headset->pending_ring = FALSE;
+ dev->headset->slc->pending_ring = FALSE;
return 0;
}
@@ -2757,7 +2811,7 @@
ag.rh = rh;
ag.chld = g_strdup(chld);
- debug("Telephony plugin initialized");
+ DBG("Telephony plugin initialized");
print_ag_features(ag.features);
@@ -2800,7 +2854,7 @@
if (!hs->hfp_active)
return -1;
- if (hs->cwa_enabled)
+ if (hs->slc->cwa_enabled)
return 0;
else
return -1;
diff --git a/audio/headset.h b/audio/headset.h
index ace1edf..8b7c738 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -29,7 +29,7 @@
typedef enum {
HEADSET_STATE_DISCONNECTED,
- HEADSET_STATE_CONNECT_IN_PROGRESS,
+ HEADSET_STATE_CONNECTING,
HEADSET_STATE_CONNECTED,
HEADSET_STATE_PLAY_IN_PROGRESS,
HEADSET_STATE_PLAYING
diff --git a/audio/ipc.c b/audio/ipc.c
index 28569dc..1bdad78 100644
--- a/audio/ipc.c
+++ b/audio/ipc.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/audio/ipc.h b/audio/ipc.h
index 2e170f5..d69b97e 100644
--- a/audio/ipc.h
+++ b/audio/ipc.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -101,6 +101,7 @@
#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
@@ -324,6 +325,16 @@
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 */
diff --git a/audio/main.c b/audio/main.c
index 9defe60..9d316ec 100644
--- a/audio/main.c
+++ b/audio/main.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -40,7 +40,7 @@
#include "glib-helper.h"
#include "btio.h"
#include "plugin.h"
-#include "logging.h"
+#include "log.h"
#include "device.h"
#include "unix.h"
#include "headset.h"
@@ -102,7 +102,7 @@
if (device->headset) {
if (headset_get_state(device) < HEADSET_STATE_CONNECTED) {
- debug("Refusing SCO from non-connected headset");
+ DBG("Refusing SCO from non-connected headset");
goto drop;
}
@@ -118,7 +118,7 @@
headset_set_state(device, HEADSET_STATE_PLAYING);
} else if (device->gateway) {
if (!gateway_is_connected(device)) {
- debug("Refusing SCO from non-connected AG");
+ DBG("Refusing SCO from non-connected AG");
goto drop;
}
@@ -130,7 +130,7 @@
sk = g_io_channel_unix_get_fd(chan);
fcntl(sk, F_SETFL, 0);
- debug("Accepted SCO connection from %s", addr);
+ DBG("Accepted SCO connection from %s", addr);
return;
diff --git a/audio/manager.c b/audio/manager.c
index ca4b1ab..6dd0f87 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -55,7 +55,7 @@
#include "../src/adapter.h"
#include "../src/device.h"
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "ipc.h"
#include "device.h"
@@ -171,14 +171,13 @@
uuid16 = uuid.value.uuid16;
if (!server_is_enabled(&device->src, uuid16)) {
- debug("audio handle_uuid: server not enabled for %s (0x%04x)",
- uuidstr, uuid16);
+ DBG("server not enabled for %s (0x%04x)", uuidstr, uuid16);
return;
}
switch (uuid16) {
case HEADSET_SVCLASS_ID:
- debug("Found Headset record");
+ DBG("Found Headset record");
if (device->headset)
headset_update(device, uuid16, uuidstr);
else
@@ -186,34 +185,34 @@
uuidstr);
break;
case HEADSET_AGW_SVCLASS_ID:
- debug("Found Headset AG record");
+ DBG("Found Headset AG record");
break;
case HANDSFREE_SVCLASS_ID:
- debug("Found Handsfree record");
+ DBG("Found Handsfree record");
if (device->headset)
headset_update(device, uuid16, uuidstr);
else
device->headset = headset_init(device, uuid16,
- uuidstr);
+ uuidstr);
break;
case HANDSFREE_AGW_SVCLASS_ID:
- debug("Found Handsfree AG record");
- if (device->gateway == NULL)
+ DBG("Found Handsfree AG record");
+ if (enabled.gateway && (device->gateway == NULL))
device->gateway = gateway_init(device);
break;
case AUDIO_SINK_SVCLASS_ID:
- debug("Found Audio Sink");
+ DBG("Found Audio Sink");
if (device->sink == NULL)
device->sink = sink_init(device);
break;
case AUDIO_SOURCE_SVCLASS_ID:
- debug("Found Audio Source");
+ 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:
- debug("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ?
+ DBG("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ?
"Remote" : "Target");
if (device->control)
control_update(device, uuid16);
@@ -223,7 +222,7 @@
avrcp_connect(device);
break;
default:
- debug("Unrecognized UUID: 0x%04X", uuid16);
+ DBG("Unrecognized UUID: 0x%04X", uuid16);
break;
}
}
@@ -309,7 +308,7 @@
sdp_set_service_classes(record, svclass_id);
sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
- profile.version = 0x0100;
+ profile.version = 0x0105;
pfseq = sdp_list_append(0, &profile);
sdp_set_profile_descs(record, pfseq);
@@ -351,12 +350,18 @@
sdp_data_t *channel, *features;
uint8_t netid = 0x01;
uint16_t sdpfeat;
- sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+ sdp_data_t *network;
record = sdp_record_alloc();
if (!record)
return NULL;
+ network = sdp_data_alloc(SDP_UINT8, &netid);
+ if (!network) {
+ sdp_record_free(record);
+ return NULL;
+ }
+
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
root = sdp_list_append(0, &root_uuid);
sdp_set_browse_groups(record, root);
@@ -411,6 +416,11 @@
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);
@@ -427,6 +437,22 @@
}
}
+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;
@@ -463,7 +489,7 @@
goto drop;
if (!manager_allow_headset_connection(device)) {
- debug("Refusing headset: too many existing connections");
+ DBG("Refusing headset: too many existing connections");
goto drop;
}
@@ -474,7 +500,7 @@
}
if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
- debug("Refusing new connection since one already exists");
+ DBG("Refusing new connection since one already exists");
goto drop;
}
@@ -485,16 +511,20 @@
goto drop;
}
- headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);
+ headset_set_state(device, HEADSET_STATE_CONNECTING);
perr = audio_device_request_authorization(device, server_uuid,
headset_auth_cb, device);
if (perr < 0) {
- debug("Authorization denied: %s", strerror(-perr));
+ 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;
@@ -513,7 +543,7 @@
char ag_address[18];
ba2str(&device->dst, ag_address);
- debug("Accepted AG connection from %s for %s",
+ DBG("Accepted AG connection from %s for %s",
ag_address, device->path);
gateway_start_service(device);
@@ -542,8 +572,8 @@
return;
}
- server_uuid = HFP_HS_UUID;
- remote_uuid = HFP_AG_UUID;
+ server_uuid = HFP_AG_UUID;
+ remote_uuid = HFP_HS_UUID;
svclass = HANDSFREE_AGW_SVCLASS_ID;
device = manager_get_device(&src, &dst, TRUE);
@@ -557,7 +587,7 @@
}
if (gateway_is_connected(device)) {
- debug("Refusing new connection since one already exists");
+ DBG("Refusing new connection since one already exists");
goto drop;
}
@@ -569,7 +599,7 @@
perr = audio_device_request_authorization(device, server_uuid,
gateway_auth_cb, device);
if (perr < 0) {
- debug("Authorization denied!");
+ DBG("Authorization denied!");
goto drop;
}
@@ -578,7 +608,6 @@
drop:
g_io_channel_shutdown(chan, TRUE, NULL);
g_io_channel_unref(chan);
- return;
}
static int headset_server_init(struct audio_adapter *adapter)
@@ -597,7 +626,7 @@
tmp = g_key_file_get_boolean(config, "General", "Master",
&err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else
master = tmp;
@@ -695,7 +724,7 @@
tmp = g_key_file_get_boolean(config, "General", "Master",
&err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else
master = tmp;
@@ -746,7 +775,7 @@
audio_dev = manager_get_device(&src, &dst, TRUE);
if (!audio_dev) {
- debug("audio_probe: unable to get a device object");
+ DBG("unable to get a device object");
return -1;
}
@@ -769,13 +798,14 @@
devices = g_slist_remove(devices, dev);
audio_device_unregister(dev);
+
}
static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp)
{
adp->ref++;
- debug("audio_adapter_ref(%p): ref=%d", adp, adp->ref);
+ DBG("%p: ref=%d", adp, adp->ref);
return adp;
}
@@ -784,7 +814,7 @@
{
adp->ref--;
- debug("audio_adapter_unref(%p): ref=%d", adp, adp->ref);
+ DBG("%p: ref=%d", adp, adp->ref);
if (adp->ref > 0)
return;
@@ -824,7 +854,7 @@
{
struct audio_adapter *adp;
const gchar *path = adapter_get_path(adapter);
- int ret;
+ int err;
DBG("path %s", path);
@@ -832,13 +862,11 @@
if (!adp)
return -EINVAL;
- ret = headset_server_init(adp);
- if (ret < 0) {
+ err = headset_server_init(adp);
+ if (err < 0)
audio_adapter_unref(adp);
- return ret;
- }
- return 0;
+ return err;
}
static void headset_server_remove(struct btd_adapter *adapter)
@@ -880,22 +908,12 @@
static int gateway_server_probe(struct btd_adapter *adapter)
{
struct audio_adapter *adp;
- const gchar *path = adapter_get_path(adapter);
- int ret;
-
- DBG("path %s", path);
adp = audio_adapter_get(adapter);
if (!adp)
return -EINVAL;
- ret = gateway_server_init(adp);
- if (ret < 0) {
- audio_adapter_ref(adp);
- return ret;
- }
-
- return 0;
+ return gateway_server_init(adp);
}
static void gateway_server_remove(struct btd_adapter *adapter)
@@ -919,7 +937,7 @@
adp->hfp_hs_server = NULL;
}
- audio_adapter_ref(adp);
+ audio_adapter_unref(adp);
}
static int a2dp_server_probe(struct btd_adapter *adapter)
@@ -927,7 +945,7 @@
struct audio_adapter *adp;
const gchar *path = adapter_get_path(adapter);
bdaddr_t src;
- int ret;
+ int err;
DBG("path %s", path);
@@ -937,13 +955,11 @@
adapter_get_address(adapter, &src);
- ret = a2dp_register(connection, &src, config);
- if (ret < 0) {
+ err = a2dp_register(connection, &src, config);
+ if (err < 0)
audio_adapter_unref(adp);
- return ret;
- }
- return 0;
+ return err;
}
static void a2dp_server_remove(struct btd_adapter *adapter)
@@ -1079,7 +1095,7 @@
b = g_key_file_get_boolean(config, "General", "AutoConnect", &err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else
auto_connect = b;
@@ -1095,7 +1111,7 @@
i = g_key_file_get_integer(config, "Headset", "MaxConnected",
&err);
if (err) {
- debug("audio.conf: %s", err->message);
+ DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else
max_connected_headsets = i;
diff --git a/audio/manager.h b/audio/manager.h
index cb9d63c..8e1abf4 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/audio/module-bluetooth-sink.c b/audio/module-bluetooth-sink.c
index 2944d18..a0117c0 100644
--- a/audio/module-bluetooth-sink.c
+++ b/audio/module-bluetooth-sink.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c
index 13cf3ee..4c0ab6f 100644
--- a/audio/pcm_bluetooth.c
+++ b/audio/pcm_bluetooth.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -1007,7 +1007,7 @@
snd_pcm_sframes_t ret = 0;
unsigned int bytes_left;
int frame_size, encoded;
- size_t written;
+ ssize_t written;
uint8_t *buff;
DBG("areas->step=%u areas->first=%u offset=%lu size=%lu",
diff --git a/audio/rtp.h b/audio/rtp.h
index 1457362..45fddcf 100644
--- a/audio/rtp.h
+++ b/audio/rtp.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
diff --git a/audio/sink.c b/audio/sink.c
index 90bceab..94fe9f2 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -36,7 +36,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "device.h"
#include "avdtp.h"
@@ -176,9 +176,9 @@
struct audio_device *device = user_data;
struct sink *sink = device->sink;
- debug("Sink: disconnect %s", device->path);
+ DBG("Sink: disconnect %s", device->path);
- avdtp_close(sink->session, sink->stream);
+ avdtp_close(sink->session, sink->stream, TRUE);
}
static void stream_state_changed(struct avdtp_stream *stream,
@@ -282,14 +282,14 @@
sink->retry_id = 0;
if (sink->stream_state >= AVDTP_STATE_OPEN) {
- debug("Stream successfully created, after XCASE connect:connect");
+ 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 {
- debug("Stream setup failed, after XCASE connect:connect");
+ DBG("Stream setup failed, after XCASE connect:connect");
if (pending->msg)
error_failed(pending->conn, pending->msg, "Stream setup failed");
}
@@ -312,7 +312,7 @@
pending->id = 0;
if (stream) {
- debug("Stream successfully created");
+ DBG("Stream successfully created");
if (pending->msg) {
DBusMessage *reply;
@@ -330,7 +330,7 @@
sink->session = NULL;
if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
- debug("connect:connect XCASE detected");
+ DBG("connect:connect XCASE detected");
sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
stream_setup_retry,
sink);
@@ -339,7 +339,7 @@
error_failed(pending->conn, pending->msg, "Stream setup failed");
sink->connect = NULL;
pending_request_free(sink->dev, pending);
- debug("Stream setup failed : %s", avdtp_strerror(err));
+ DBG("Stream setup failed : %s", avdtp_strerror(err));
}
}
@@ -475,6 +475,12 @@
*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;
}
@@ -497,7 +503,7 @@
sink->session = NULL;
if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
- debug("connect:connect XCASE detected");
+ DBG("connect:connect XCASE detected");
sink->retry_id =
g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
stream_setup_retry,
@@ -507,7 +513,7 @@
return;
}
- debug("Discovery complete");
+ DBG("Discovery complete");
if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
@@ -597,7 +603,7 @@
pending->conn = dbus_connection_ref(conn);
pending->msg = dbus_message_ref(msg);
- debug("stream creation in progress");
+ DBG("stream creation in progress");
return NULL;
}
@@ -628,7 +634,7 @@
return reply;
}
- err = avdtp_close(sink->session, sink->stream);
+ err = avdtp_close(sink->session, sink->stream, FALSE);
if (err < 0)
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
"%s", strerror(-err));
@@ -825,7 +831,7 @@
{
struct audio_device *dev = data;
- debug("Unregistered interface %s on path %s",
+ DBG("Unregistered interface %s on path %s",
AUDIO_SINK_INTERFACE, dev->path);
sink_free(dev);
@@ -847,7 +853,7 @@
dev, path_unregister))
return NULL;
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
AUDIO_SINK_INTERFACE, dev->path);
if (avdtp_callback_id == 0)
@@ -902,7 +908,7 @@
if (!sink->stream)
return FALSE;
- if (avdtp_close(sink->session, sink->stream) < 0)
+ if (avdtp_close(sink->session, sink->stream, FALSE) < 0)
return FALSE;
return TRUE;
diff --git a/audio/sink.h b/audio/sink.h
index 3f822bc..7b1902b 100644
--- a/audio/sink.h
+++ b/audio/sink.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/audio/source.c b/audio/source.c
index 1cec1f6..35d8136 100644
--- a/audio/source.c
+++ b/audio/source.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2009 Joao Paulo Rechi Vita
*
*
@@ -37,7 +37,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "device.h"
#include "avdtp.h"
@@ -169,9 +169,9 @@
struct audio_device *device = user_data;
struct source *source = device->source;
- debug("Source: disconnect %s", device->path);
+ DBG("Source: disconnect %s", device->path);
- avdtp_close(source->session, source->stream);
+ avdtp_close(source->session, source->stream, TRUE);
}
static void stream_state_changed(struct avdtp_stream *stream,
@@ -249,14 +249,14 @@
source->retry_id = 0;
if (source->stream_state >= AVDTP_STATE_OPEN) {
- debug("Stream successfully created, after XCASE connect:connect");
+ 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 {
- debug("Stream setup failed, after XCASE connect:connect");
+ DBG("Stream setup failed, after XCASE connect:connect");
if (pending->msg)
error_failed(pending->conn, pending->msg, "Stream setup failed");
}
@@ -279,7 +279,7 @@
pending->id = 0;
if (stream) {
- debug("Stream successfully created");
+ DBG("Stream successfully created");
if (pending->msg) {
DBusMessage *reply;
@@ -297,7 +297,7 @@
source->session = NULL;
if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
- debug("connect:connect XCASE detected");
+ DBG("connect:connect XCASE detected");
source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
stream_setup_retry,
source);
@@ -306,7 +306,7 @@
error_failed(pending->conn, pending->msg, "Stream setup failed");
source->connect = NULL;
pending_request_free(source->dev, pending);
- debug("Stream setup failed : %s", avdtp_strerror(err));
+ DBG("Stream setup failed : %s", avdtp_strerror(err));
}
}
@@ -464,7 +464,7 @@
source->session = NULL;
if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
- debug("connect:connect XCASE detected");
+ DBG("connect:connect XCASE detected");
source->retry_id =
g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
stream_setup_retry,
@@ -474,7 +474,7 @@
return;
}
- debug("Discovery complete");
+ DBG("Discovery complete");
if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
@@ -565,7 +565,7 @@
pending->conn = dbus_connection_ref(conn);
pending->msg = dbus_message_ref(msg);
- debug("stream creation in progress");
+ DBG("stream creation in progress");
return NULL;
}
@@ -596,7 +596,7 @@
return reply;
}
- err = avdtp_close(source->session, source->stream);
+ err = avdtp_close(source->session, source->stream, FALSE);
if (err < 0)
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
"%s", strerror(-err));
@@ -685,7 +685,7 @@
{
struct audio_device *dev = data;
- debug("Unregistered interface %s on path %s",
+ DBG("Unregistered interface %s on path %s",
AUDIO_SOURCE_INTERFACE, dev->path);
source_free(dev);
@@ -707,7 +707,7 @@
dev, path_unregister))
return NULL;
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
AUDIO_SOURCE_INTERFACE, dev->path);
if (avdtp_callback_id == 0)
@@ -762,7 +762,7 @@
if (!source->stream)
return FALSE;
- if (avdtp_close(source->session, source->stream) < 0)
+ if (avdtp_close(source->session, source->stream, FALSE) < 0)
return FALSE;
return TRUE;
diff --git a/audio/source.h b/audio/source.h
index 8250814..7837284 100644
--- a/audio/source.h
+++ b/audio/source.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2009 Joao Paulo Rechi Vita
*
*
diff --git a/audio/telephony-dummy.c b/audio/telephony-dummy.c
index deb604c..06cb798 100644
--- a/audio/telephony-dummy.c
+++ b/audio/telephony-dummy.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -33,9 +33,14 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "telephony.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;
@@ -72,12 +77,12 @@
void telephony_device_connected(void *telephony_device)
{
- debug("telephony-dummy: device %p connected", telephony_device);
+ DBG("telephony-dummy: device %p connected", telephony_device);
}
void telephony_device_disconnected(void *telephony_device)
{
- debug("telephony-dummy: device %p disconnected", telephony_device);
+ DBG("telephony-dummy: device %p disconnected", telephony_device);
events_enabled = FALSE;
}
@@ -142,7 +147,7 @@
g_free(active_call_number);
active_call_number = g_strdup(number);
- debug("telephony-dummy: dial request to %s", active_call_number);
+ DBG("telephony-dummy: dial request to %s", active_call_number);
telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
@@ -158,13 +163,13 @@
void telephony_transmit_dtmf_req(void *telephony_device, char tone)
{
- debug("telephony-dummy: transmit dtmf: %c", 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)
{
- debug("telephony-dummy: subscriber number request");
+ DBG("telephony-dummy: subscriber number request");
if (subscriber_number)
telephony_subscriber_number_ind(subscriber_number,
NUMBER_TYPE_TELEPHONY,
@@ -174,7 +179,7 @@
void telephony_list_current_calls_req(void *telephony_device)
{
- debug("telephony-dummy: list current calls request");
+ DBG("telephony-dummy: list current calls request");
if (active_call_number)
telephony_list_current_call_ind(1, active_call_dir,
active_call_status,
@@ -193,21 +198,33 @@
void telephony_call_hold_req(void *telephony_device, const char *cmd)
{
- debug("telephony-dymmy: got call hold request %s", 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)
{
- debug("telephony-dummy: got %s NR and EC request",
+ 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)
{
- debug("telephony-dummy: got key press request for %s", keys);
+ DBG("telephony-dummy: got key press request for %s", keys);
telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
}
@@ -221,7 +238,7 @@
DBUS_TYPE_INVALID))
return invalid_args(msg);
- debug("telephony-dummy: outgoing call to %s", number);
+ DBG("telephony-dummy: outgoing call to %s", number);
g_free(active_call_number);
active_call_number = g_strdup(number);
@@ -246,7 +263,7 @@
DBUS_TYPE_INVALID))
return invalid_args(msg);
- debug("telephony-dummy: incoming call to %s", number);
+ DBG("telephony-dummy: incoming call to %s", number);
g_free(active_call_number);
active_call_number = g_strdup(number);
@@ -265,7 +282,7 @@
static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- debug("telephony-dummy: cancel call");
+ DBG("telephony-dummy: cancel call");
g_free(active_call_number);
active_call_number = NULL;
@@ -297,7 +314,7 @@
telephony_update_indicator(dummy_indicators, "signal", strength);
- debug("telephony-dummy: signal strength set to %u", strength);
+ DBG("telephony-dummy: signal strength set to %u", strength);
return dbus_message_new_method_return(msg);
}
@@ -316,7 +333,7 @@
telephony_update_indicator(dummy_indicators, "battchg", level);
- debug("telephony-dummy: battery level set to %u", level);
+ DBG("telephony-dummy: battery level set to %u", level);
return dbus_message_new_method_return(msg);
}
@@ -335,7 +352,7 @@
telephony_update_indicator(dummy_indicators, "roam", val);
- debug("telephony-dummy: roaming status set to %d", val);
+ DBG("telephony-dummy: roaming status set to %d", val);
return dbus_message_new_method_return(msg);
}
@@ -354,7 +371,7 @@
telephony_update_indicator(dummy_indicators, "service", val);
- debug("telephony-dummy: registration status set to %d", val);
+ DBG("telephony-dummy: registration status set to %d", val);
return dbus_message_new_method_return(msg);
}
@@ -372,7 +389,7 @@
g_free(subscriber_number);
subscriber_number = g_strdup(number);
- debug("telephony-dummy: subscriber number set to %s", number);
+ DBG("telephony-dummy: subscriber number set to %s", number);
return dbus_message_new_method_return(msg);
}
@@ -389,7 +406,10 @@
{ }
};
-static DBusConnection *connection = NULL;
+static GDBusSignalTable dummy_signals[] = {
+ { "VoiceDial", "" },
+ { }
+};
int telephony_init(void)
{
@@ -399,10 +419,14 @@
connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
- g_dbus_register_interface(connection, "/org/bluez/test",
- "org.bluez.TelephonyTest",
- dummy_methods, NULL,
- NULL, NULL, 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, response_and_hold,
chld_str);
diff --git a/audio/telephony-maemo.c b/audio/telephony-maemo5.c
similarity index 90%
rename from audio/telephony-maemo.c
rename to audio/telephony-maemo5.c
index f302cdf..4d0134c 100644
--- a/audio/telephony-maemo.c
+++ b/audio/telephony-maemo5.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2008-2009 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -36,9 +36,14 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "telephony.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"
@@ -101,6 +106,7 @@
#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
@@ -181,8 +187,6 @@
.operator_name = NULL,
};
-static guint csd_watch = 0;
-
static DBusConnection *connection = NULL;
static GSList *calls = NULL;
@@ -198,6 +202,8 @@
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 */
@@ -219,8 +225,8 @@
static struct indicator maemo_indicators[] =
{
{ "battchg", "0-5", 5, TRUE },
- { "signal", "0-5", 5, TRUE },
- { "service", "0,1", 1, 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 },
@@ -308,6 +314,26 @@
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;
@@ -462,7 +488,7 @@
{
struct csd_call *coming;
- debug("telephony-maemo: device %p connected", telephony_device);
+ DBG("telephony-maemo: device %p connected", telephony_device);
coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
if (coming) {
@@ -477,7 +503,7 @@
void telephony_device_disconnected(void *telephony_device)
{
- debug("telephony-maemo: device %p disconnected", telephony_device);
+ DBG("telephony-maemo: device %p disconnected", telephony_device);
events_enabled = FALSE;
}
@@ -499,7 +525,7 @@
void telephony_last_dialed_number_req(void *telephony_device)
{
- debug("telephony-maemo: last dialed number request");
+ DBG("telephony-maemo: last dialed number request");
if (last_dialed_number)
telephony_dial_number_req(telephony_device,
@@ -512,6 +538,7 @@
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)
@@ -524,7 +551,12 @@
return;
}
- if (release_call(call) < 0)
+ 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
@@ -614,7 +646,7 @@
uint32_t flags = callerid;
int ret;
- debug("telephony-maemo: dial request to %s", number);
+ DBG("telephony-maemo: dial request to %s", number);
if (strncmp(number, "*31#", 4) == 0) {
number += 4;
@@ -654,7 +686,7 @@
int ret;
char buf[2] = { tone, '\0' }, *buf_ptr = buf;
- debug("telephony-maemo: transmit dtmf: %s", buf);
+ DBG("telephony-maemo: transmit dtmf: %s", buf);
ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
CSD_CALL_INTERFACE, "SendDTMF",
@@ -672,7 +704,7 @@
void telephony_subscriber_number_req(void *telephony_device)
{
- debug("telephony-maemo: subscriber number request");
+ DBG("telephony-maemo: subscriber number request");
if (msisdn)
telephony_subscriber_number_ind(msisdn,
number_type(msisdn),
@@ -723,7 +755,7 @@
GSList *l;
int i;
- debug("telephony-maemo: list current calls request");
+ DBG("telephony-maemo: list current calls request");
for (l = calls, i = 1; l != NULL; l = l->next, i++) {
struct csd_call *call = l->data;
@@ -774,7 +806,7 @@
struct csd_call *call;
int err = 0;
- debug("telephony-maemo: got call hold request %s", cmd);
+ DBG("telephony-maemo: got call hold request %s", cmd);
if (strlen(cmd) > 1)
idx = &cmd[1];
@@ -835,7 +867,7 @@
err = call_transfer();
break;
default:
- debug("Unknown call hold request");
+ DBG("Unknown call hold request");
break;
}
@@ -848,7 +880,7 @@
void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
{
- debug("telephony-maemo: got %s NR and EC request",
+ DBG("telephony-maemo: got %s NR and EC request",
enable ? "enable" : "disable");
telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
}
@@ -858,7 +890,7 @@
struct csd_call *active, *waiting;
int err;
- debug("telephony-maemo: got key press request for %s", keys);
+ DBG("telephony-maemo: got key press request for %s", keys);
waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
if (!waiting)
@@ -882,6 +914,14 @@
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;
@@ -902,7 +942,7 @@
return;
}
- debug("Incoming call to %s from number %s", call_path, number);
+ DBG("Incoming call to %s from number %s", call_path, number);
g_free(call->number);
call->number = g_strdup(number);
@@ -938,7 +978,7 @@
return;
}
- debug("Outgoing call from %s to number %s", call_path, number);
+ DBG("Outgoing call from %s to number %s", call_path, number);
g_free(call->number);
call->number = g_strdup(number);
@@ -962,7 +1002,7 @@
static void handle_create_requested(DBusMessage *msg)
{
- debug("Call.CreateRequested()");
+ DBG("Call.CreateRequested()");
if (create_request_timer)
g_source_remove(create_request_timer);
@@ -1000,11 +1040,11 @@
return;
}
- debug("Call %s changed from %s to %s", call_path,
+ DBG("Call %s changed from %s to %s", call_path,
call_status_str[call->status], call_status_str[status]);
if (call->status == (int) status) {
- debug("Ignoring CSD Call state change to existing state");
+ DBG("Ignoring CSD Call state change to existing state");
return;
}
@@ -1142,7 +1182,7 @@
return;
}
- debug("Call %s %s the conference", path, joined ? "joined" : "left");
+ DBG("Call %s %s the conference", path, joined ? "joined" : "left");
call->conference = joined;
}
@@ -1187,7 +1227,7 @@
g_free(net.operator_name);
net.operator_name = g_strdup(name);
- debug("telephony-maemo: operator name updated: %s", name);
+ DBG("telephony-maemo: operator name updated: %s", name);
done:
dbus_message_unref(reply);
@@ -1295,7 +1335,7 @@
int signal;
if (signals_bar > 100) {
- debug("signals_bar greater than expected: %u", signals_bar);
+ DBG("signals_bar greater than expected: %u", signals_bar);
signals_bar = 100;
}
@@ -1309,7 +1349,7 @@
net.signals_bar = signals_bar;
- debug("Signal strength updated: %u/100, %d/5", signals_bar, signal);
+ DBG("Signal strength updated: %u/100, %d/5", signals_bar, signal);
}
static void handle_signal_strength_change(DBusMessage *msg)
@@ -1372,20 +1412,26 @@
goto done;
}
- dbus_message_get_args(reply, NULL,
+ dbus_error_init(&err);
+ if (dbus_message_get_args(reply, &err,
DBUS_TYPE_INT32, &level,
- DBUS_TYPE_INVALID);
+ 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)
- debug("telephony-maemo: battery.charge_level.last_full is %d",
+ DBG("telephony-maemo: battery.charge_level.last_full is %d",
*value);
else if (value == &battchg_design)
- debug("telephony-maemo: battery.charge_level.design is %d",
+ DBG("telephony-maemo: battery.charge_level.design is %d",
*value);
else
- debug("telephony-maemo: battery.charge_level.current is %d",
+ DBG("telephony-maemo: battery.charge_level.current is %d",
*value);
if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
@@ -1466,40 +1512,6 @@
}
}
-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);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
static void csd_call_free(struct csd_call *call)
{
if (!call)
@@ -1547,7 +1559,7 @@
call->object_path = g_strdup(object_path);
call->status = (int) status;
calls = g_slist_append(calls, call);
- debug("telephony-maemo: new csd call instance at %s",
+ DBG("telephony-maemo: new csd call instance at %s",
object_path);
}
@@ -1589,7 +1601,7 @@
}
dbus_error_init(&err);
- if (!dbus_message_get_args(reply, NULL,
+ if (!dbus_message_get_args(reply, &err,
DBUS_TYPE_BYTE, &signals_bar,
DBUS_TYPE_BYTE, &rssi_in_dbm,
DBUS_TYPE_INT32, &net_err,
@@ -1627,13 +1639,6 @@
dbus_uint16_t lac, network_type, supported_services;
dbus_uint32_t cell_id, operator_code, country_code;
dbus_int32_t net_err;
- 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;
reply = dbus_pending_call_steal_reply(call);
@@ -1646,7 +1651,7 @@
}
dbus_error_init(&err);
- if (!dbus_message_get_args(reply, NULL,
+ if (!dbus_message_get_args(reply, &err,
DBUS_TYPE_BYTE, &status,
DBUS_TYPE_UINT16, &lac,
DBUS_TYPE_UINT32, &cell_id,
@@ -1671,9 +1676,6 @@
country_code, network_type,
supported_services);
- telephony_ready_ind(features, maemo_indicators, response_and_hold,
- chld_str);
-
get_signal_strength();
done:
@@ -1694,6 +1696,8 @@
DBusMessage *reply;
DBusMessageIter iter, sub;;
+ get_calls_active = FALSE;
+
reply = dbus_pending_call_steal_reply(call);
dbus_error_init(&err);
@@ -1743,7 +1747,7 @@
dbus_message_iter_init(reply, &iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in GetCallInfoAll return");
+ error("Unexpected signature in FindDeviceByCapability return");
goto done;
}
@@ -1758,7 +1762,7 @@
dbus_message_iter_get_basic(&sub, &path);
- debug("telephony-maemo: found battery device at %s", path);
+ DBG("telephony-maemo: found battery device at %s", path);
snprintf(match_string, sizeof(match_string),
"type='signal',"
@@ -1794,14 +1798,12 @@
}
dbus_error_init(&derr);
- dbus_message_get_args(reply, NULL,
+ if (dbus_message_get_args(reply, &derr,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &number,
DBUS_TYPE_INT32, ¤t_location,
DBUS_TYPE_INT32, &err,
- DBUS_TYPE_INVALID);
-
- if (dbus_error_is_set(&derr)) {
+ DBUS_TYPE_INVALID) == FALSE) {
error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
derr.name, derr.message);
dbus_error_free(&derr);
@@ -1818,66 +1820,32 @@
if (number_type == &msisdn) {
g_free(msisdn);
msisdn = g_strdup(number);
- debug("Got MSISDN %s (%s)", number, name);
+ DBG("Got MSISDN %s (%s)", number, name);
} else {
g_free(vmbx);
vmbx = g_strdup(number);
- debug("Got voice mailbox number %s (%s)", number, name);
+ DBG("Got voice mailbox number %s (%s)", number, name);
}
done:
dbus_message_unref(reply);
}
-static gboolean csd_init(gpointer user_data)
+static void csd_init(void)
{
- char match_string[128];
- const char *battery_cap = "battery";
dbus_uint32_t location;
uint8_t pb_type, location_type;
int ret;
- if (!dbus_connection_add_filter(connection, signal_filter,
- NULL, NULL)) {
- error("Can't add signal filter");
- return FALSE;
- }
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", CSD_CALL_INTERFACE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", CSD_CALL_INSTANCE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", CSD_CALL_CONFERENCE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", NETWORK_INTERFACE);
- dbus_bus_add_match(connection, match_string, NULL);
-
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 FALSE;
+ return;
}
- 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) {
- error("Unable to send HAL method call");
- return FALSE;
- }
+ get_calls_active = TRUE;
pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
location = PHONEBOOK_INDEX_FIRST_ENTRY;
@@ -1892,10 +1860,10 @@
DBUS_TYPE_INVALID);
if (ret < 0) {
error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return FALSE;
+ return;
}
- pb_type = SIM_PHONEBOOK_TYPE_VMBX;
+ pb_type = SIM_PHONEBOOK_TYPE_MBDN;
location = PHONEBOOK_INDEX_FIRST_ENTRY;
location_type = SIM_PHONEBOOK_LOCATION_NEXT;
@@ -1908,18 +1876,8 @@
DBUS_TYPE_INVALID);
if (ret < 0) {
error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return FALSE;
+ return;
}
-
- return FALSE;
-}
-
-static void csd_ready(DBusConnection *conn, void *user_data)
-{
- g_dbus_remove_watch(conn, csd_watch);
- csd_watch = 0;
-
- g_timeout_add_seconds(2, csd_init, NULL);
}
static inline DBusMessage *invalid_args(DBusMessage *msg)
@@ -1999,7 +1957,7 @@
g_str_equal(callerid_setting, "none")) {
save_callerid_to_file(callerid_setting);
callerid = get_callflag(callerid_setting);
- debug("telephony-maemo setting callerid flag: %s",
+ DBG("telephony-maemo setting callerid flag: %s",
callerid_setting);
return dbus_message_new_method_return(msg);
}
@@ -2015,17 +1973,110 @@
{ }
};
+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);
- csd_watch = g_dbus_add_service_watch(connection, CSD_CALL_BUS_NAME,
- csd_ready, NULL, NULL, NULL);
+ if (!dbus_connection_add_filter(connection, signal_filter,
+ NULL, NULL))
+ error("Can't add signal filter");
- if (dbus_bus_name_has_owner(connection, CSD_CALL_BUS_NAME, NULL))
- csd_ready(connection, NULL);
- else
- info("CSD not yet available. Waiting for it...");
+ 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();
@@ -2037,19 +2088,25 @@
TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
}
- debug("telephony-maemo registering %s interface on path %s",
+ DBG("telephony-maemo registering %s interface on path %s",
TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
+ telephony_ready_ind(features, maemo_indicators, response_and_hold,
+ 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)
{
- if (csd_watch) {
- g_dbus_remove_watch(connection, csd_watch);
- csd_watch = 0;
- }
-
g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
g_slist_free(calls);
calls = NULL;
diff --git a/audio/telephony-maemo.c b/audio/telephony-maemo6.c
similarity index 73%
copy from audio/telephony-maemo.c
copy to audio/telephony-maemo6.c
index f302cdf..046620c 100644
--- a/audio/telephony-maemo.c
+++ b/audio/telephony-maemo6.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2008-2009 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -36,55 +36,36 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "telephony.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
+#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 = 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
+ 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
};
-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,
-};
-
+/* Driver definitions */
#define TELEPHONY_MAEMO_PATH "/com/nokia/MaemoTelephony"
#define TELEPHONY_MAEMO_INTERFACE "com.nokia.MaemoTelephony"
@@ -101,6 +82,7 @@
#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
@@ -126,27 +108,17 @@
#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 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 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
-};
+#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"
struct csd_call {
char *object_path;
@@ -160,28 +132,19 @@
};
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;
+ uint8_t status;
+ int32_t signal_bars;
} 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,
+ .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,
};
-static guint csd_watch = 0;
+static int get_property(const char *iface, const char *prop);
static DBusConnection *connection = NULL;
@@ -198,6 +161,8 @@
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 */
@@ -219,8 +184,9 @@
static struct indicator maemo_indicators[] =
{
{ "battchg", "0-5", 5, TRUE },
- { "signal", "0-5", 5, TRUE },
- { "service", "0,1", 1, 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 },
@@ -308,6 +274,26 @@
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;
@@ -462,7 +448,7 @@
{
struct csd_call *coming;
- debug("telephony-maemo: device %p connected", telephony_device);
+ DBG("telephony-maemo6: device %p connected", telephony_device);
coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
if (coming) {
@@ -477,7 +463,7 @@
void telephony_device_disconnected(void *telephony_device)
{
- debug("telephony-maemo: device %p disconnected", telephony_device);
+ DBG("telephony-maemo6: device %p disconnected", telephony_device);
events_enabled = FALSE;
}
@@ -499,7 +485,7 @@
void telephony_last_dialed_number_req(void *telephony_device)
{
- debug("telephony-maemo: last dialed number request");
+ DBG("telephony-maemo6: last dialed number request");
if (last_dialed_number)
telephony_dial_number_req(telephony_device,
@@ -512,6 +498,7 @@
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)
@@ -524,7 +511,12 @@
return;
}
- if (release_call(call) < 0)
+ 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
@@ -614,7 +606,7 @@
uint32_t flags = callerid;
int ret;
- debug("telephony-maemo: dial request to %s", number);
+ DBG("telephony-maemo6: dial request to %s", number);
if (strncmp(number, "*31#", 4) == 0) {
number += 4;
@@ -654,7 +646,7 @@
int ret;
char buf[2] = { tone, '\0' }, *buf_ptr = buf;
- debug("telephony-maemo: transmit dtmf: %s", buf);
+ DBG("telephony-maemo6: transmit dtmf: %s", buf);
ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
CSD_CALL_INTERFACE, "SendDTMF",
@@ -672,7 +664,7 @@
void telephony_subscriber_number_req(void *telephony_device)
{
- debug("telephony-maemo: subscriber number request");
+ DBG("telephony-maemo6: subscriber number request");
if (msisdn)
telephony_subscriber_number_ind(msisdn,
number_type(msisdn),
@@ -723,7 +715,7 @@
GSList *l;
int i;
- debug("telephony-maemo: list current calls request");
+ DBG("telephony-maemo6: list current calls request");
for (l = calls, i = 1; l != NULL; l = l->next, i++) {
struct csd_call *call = l->data;
@@ -774,7 +766,7 @@
struct csd_call *call;
int err = 0;
- debug("telephony-maemo: got call hold request %s", cmd);
+ DBG("telephony-maemo6: got call hold request %s", cmd);
if (strlen(cmd) > 1)
idx = &cmd[1];
@@ -835,7 +827,7 @@
err = call_transfer();
break;
default:
- debug("Unknown call hold request");
+ DBG("Unknown call hold request");
break;
}
@@ -848,7 +840,7 @@
void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
{
- debug("telephony-maemo: got %s NR and EC request",
+ DBG("telephony-maemo6: got %s NR and EC request",
enable ? "enable" : "disable");
telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
}
@@ -858,7 +850,7 @@
struct csd_call *active, *waiting;
int err;
- debug("telephony-maemo: got key press request for %s", keys);
+ DBG("telephony-maemo6: got key press request for %s", keys);
waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
if (!waiting)
@@ -882,6 +874,14 @@
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;
@@ -902,7 +902,7 @@
return;
}
- debug("Incoming call to %s from number %s", call_path, number);
+ DBG("Incoming call to %s from number %s", call_path, number);
g_free(call->number);
call->number = g_strdup(number);
@@ -938,7 +938,7 @@
return;
}
- debug("Outgoing call from %s to number %s", call_path, number);
+ DBG("Outgoing call from %s to number %s", call_path, number);
g_free(call->number);
call->number = g_strdup(number);
@@ -962,7 +962,7 @@
static void handle_create_requested(DBusMessage *msg)
{
- debug("Call.CreateRequested()");
+ DBG("Call.CreateRequested()");
if (create_request_timer)
g_source_remove(create_request_timer);
@@ -1000,11 +1000,11 @@
return;
}
- debug("Call %s changed from %s to %s", call_path,
+ DBG("Call %s changed from %s to %s", call_path,
call_status_str[call->status], call_status_str[status]);
if (call->status == (int) status) {
- debug("Ignoring CSD Call state change to existing state");
+ DBG("Ignoring CSD Call state change to existing state");
return;
}
@@ -1142,189 +1142,128 @@
return;
}
- debug("Call %s %s the conference", path, joined ? "joined" : "left");
+ 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)
+static uint8_t str2status(const char *state)
{
- 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);
-
- debug("telephony-maemo: operator name updated: %s", name);
-
-done:
- dbus_message_unref(reply);
+ 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 resolve_operator_name(uint32_t operator, uint32_t country)
+static void update_registration_status(const char *status)
{
- uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME;
+ uint8_t new_status;
- 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);
-}
+ new_status = str2status(status);
-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",
+ 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_NOSERV)
- telephony_update_indicator(maemo_indicators,
+ if (net.status > NETWORK_REG_STATUS_ROAMING)
+ 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",
+ break;
+ case NETWORK_REG_STATUS_ROAMING:
+ telephony_update_indicator(maemo_indicators, "roam",
EV_ROAM_ACTIVE);
- if (net.status >= NETWORK_REG_STATUS_NOSERV)
- telephony_update_indicator(maemo_indicators,
+ if (net.status > NETWORK_REG_STATUS_ROAMING)
+ 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,
+ 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 = status;
+ break;
}
- net.lac = lac;
- net.cell_id = cell_id;
+ net.status = new_status;
- 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;
+ DBG("telephony-maemo6: registration status changed: %s", status);
}
-static void handle_registration_status_change(DBusMessage *msg)
+static void handle_registration_changed(DBusMessage *msg)
{
- uint8_t status;
- dbus_uint16_t lac, network_type, supported_services;
- dbus_uint32_t cell_id, operator_code, country_code;
+ const char *status;
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_STRING, &status,
DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in registration_status_change");
+ error("Unexpected parameters in RegistrationChanged");
return;
}
- update_registration_status(status, lac, cell_id, operator_code,
- country_code, network_type,
- supported_services);
+ update_registration_status(status);
}
-static void update_signal_strength(uint8_t signals_bar)
+static void update_signal_strength(int32_t signal_bars)
{
- int signal;
-
- if (signals_bar > 100) {
- debug("signals_bar greater than expected: %u", signals_bar);
- signals_bar = 100;
+ if (signal_bars < 0) {
+ DBG("signal strength smaller than expected: %d < 0",
+ signal_bars);
+ signal_bars = 0;
+ } else if (signal_bars > 5) {
+ DBG("signal strength greater than expected: %d > 5",
+ signal_bars);
+ signal_bars = 5;
}
- if (net.signals_bar == signals_bar)
+ if (net.signal_bars == signal_bars)
return;
- /* A simple conversion from 0-100 to 0-5 (used by HFP) */
- signal = (signals_bar + 20) / 21;
+ telephony_update_indicator(maemo_indicators, "signal", signal_bars);
- telephony_update_indicator(maemo_indicators, "signal", signal);
-
- net.signals_bar = signals_bar;
-
- debug("Signal strength updated: %u/100, %d/5", signals_bar, signal);
+ net.signal_bars = signal_bars;
+ DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
}
-static void handle_signal_strength_change(DBusMessage *msg)
+static void handle_signal_bars_changed(DBusMessage *msg)
{
- uint8_t signals_bar, rssi_in_dbm;
+ int32_t signal_bars;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_BYTE, &signals_bar,
- DBUS_TYPE_BYTE, &rssi_in_dbm,
+ DBUS_TYPE_INT32, &signal_bars,
DBUS_TYPE_INVALID)) {
- error("Unexpected parameters in signal_strength_change");
+ error("Unexpected parameters in SignalBarsChanged");
return;
}
- update_signal_strength(signals_bar);
+ update_signal_strength(signal_bars);
}
static gboolean iter_get_basic_args(DBusMessageIter *iter,
@@ -1372,20 +1311,23 @@
goto done;
}
- dbus_message_get_args(reply, NULL,
+ if (!dbus_message_get_args(reply, NULL,
DBUS_TYPE_INT32, &level,
- DBUS_TYPE_INVALID);
+ DBUS_TYPE_INVALID)) {
+ error("Unexpected args in hald reply");
+ goto done;
+ }
*value = (int) level;
if (value == &battchg_last)
- debug("telephony-maemo: battery.charge_level.last_full is %d",
+ DBG("telephony-maemo6: battery.charge_level.last_full is %d",
*value);
else if (value == &battchg_design)
- debug("telephony-maemo: battery.charge_level.design is %d",
+ DBG("telephony-maemo6: battery.charge_level.design is %d",
*value);
else
- debug("telephony-maemo: battery.charge_level.current is %d",
+ DBG("telephony-maemo6: battery.charge_level.current is %d",
*value);
if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
@@ -1466,40 +1408,6 @@
}
}
-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);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
static void csd_call_free(struct csd_call *call)
{
if (!call)
@@ -1547,7 +1455,7 @@
call->object_path = g_strdup(object_path);
call->status = (int) status;
calls = g_slist_append(calls, call);
- debug("telephony-maemo: new csd call instance at %s",
+ DBG("telephony-maemo6: new csd call instance at %s",
object_path);
}
@@ -1571,129 +1479,100 @@
} while (dbus_message_iter_next(iter));
}
-static void signal_strength_reply(DBusPendingCall *call, void *user_data)
+static void update_operator_name(const char *name)
{
+ if (name == NULL)
+ return;
+
+ g_free(net.operator_name);
+ net.operator_name = g_strdup(name);
+
+ 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;
- uint8_t signals_bar, rssi_in_dbm;
- dbus_int32_t net_err;
+ DBusMessageIter iter, sub;
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, NULL,
- 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);
- return;
- }
-
- if (net_err != 0) {
- error("get_signal_strength failed with code %d", net_err);
- return;
- }
-
- 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;
- 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;
-
- 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",
+ error("csd 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, 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_INT32, &net_err,
- DBUS_TYPE_INVALID)) {
- error("Unable to parse registration_status_change reply:"
- " %s, %s", err.name, err.message);
- dbus_error_free(&err);
- return;
+ 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;
}
- if (net_err != 0) {
- error("get_registration_status failed with code %d", net_err);
- return;
+ 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);
}
- update_registration_status(status, lac, cell_id, operator_code,
- country_code, network_type,
- supported_services);
-
- telephony_ready_ind(features, maemo_indicators, response_and_hold,
- chld_str);
-
- get_signal_strength();
-
done:
+ g_free(prop);
dbus_message_unref(reply);
}
-static int get_registration_status(void)
+static int get_property(const char *iface, const char *prop)
{
- return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
- NETWORK_INTERFACE, "get_registration_status",
- registration_status_reply, NULL,
+ 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);
@@ -1715,7 +1594,7 @@
parse_call_list(&sub);
- get_registration_status();
+ get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
done:
dbus_message_unref(reply);
@@ -1743,7 +1622,7 @@
dbus_message_iter_init(reply, &iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in GetCallInfoAll return");
+ error("Unexpected signature in FindDeviceByCapability return");
goto done;
}
@@ -1758,7 +1637,7 @@
dbus_message_iter_get_basic(&sub, &path);
- debug("telephony-maemo: found battery device at %s", path);
+ DBG("telephony-maemo6: found battery device at %s", path);
snprintf(match_string, sizeof(match_string),
"type='signal',"
@@ -1779,147 +1658,90 @@
{
DBusError derr;
DBusMessage *reply;
- const char *name, *number;
+ const char *name, *number, *secondname, *additionalnumber, *email;
+ int index;
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);
+ 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);
- dbus_message_get_args(reply, NULL,
+ if (dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_INT32, &index,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &number,
- DBUS_TYPE_INT32, ¤t_location,
- DBUS_TYPE_INT32, &err,
- DBUS_TYPE_INVALID);
-
- if (dbus_error_is_set(&derr)) {
- error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
- derr.name, derr.message);
+ 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 (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);
- debug("Got MSISDN %s (%s)", number, name);
+ DBG("Got MSISDN %s (%s)", number, name);
} else {
g_free(vmbx);
vmbx = g_strdup(number);
- debug("Got voice mailbox number %s (%s)", number, name);
+ DBG("Got voice mailbox number %s (%s)", number, name);
}
done:
dbus_message_unref(reply);
}
-static gboolean csd_init(gpointer user_data)
+static void csd_init(void)
{
- char match_string[128];
- const char *battery_cap = "battery";
- dbus_uint32_t location;
- uint8_t pb_type, location_type;
+ const char *pb_type;
int ret;
- if (!dbus_connection_add_filter(connection, signal_filter,
- NULL, NULL)) {
- error("Can't add signal filter");
- return FALSE;
- }
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", CSD_CALL_INTERFACE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", CSD_CALL_INSTANCE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", CSD_CALL_CONFERENCE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string),
- "type=signal,interface=%s", NETWORK_INTERFACE);
- dbus_bus_add_match(connection, match_string, NULL);
-
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 FALSE;
+ return;
}
- 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) {
- error("Unable to send HAL method call");
- return FALSE;
- }
+ get_calls_active = TRUE;
- pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
- location = PHONEBOOK_INDEX_FIRST_ENTRY;
- location_type = SIM_PHONEBOOK_LOCATION_NEXT;
+ pb_type = CSD_SIMPB_TYPE_MSISDN;
- ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
- SIM_PHONEBOOK_INTERFACE, "read",
+ ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
+ CSD_SIMPB_INTERFACE, "ReadFirst",
phonebook_read_reply, &msisdn,
- DBUS_TYPE_BYTE, &pb_type,
- DBUS_TYPE_INT32, &location,
- DBUS_TYPE_BYTE, &location_type,
+ DBUS_TYPE_STRING, &pb_type,
DBUS_TYPE_INVALID);
if (ret < 0) {
- error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return FALSE;
+ error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
+ return;
}
- pb_type = SIM_PHONEBOOK_TYPE_VMBX;
- location = PHONEBOOK_INDEX_FIRST_ENTRY;
- location_type = SIM_PHONEBOOK_LOCATION_NEXT;
+ /* Voicemail should be in MBDN index 0 */
+ pb_type = CSD_SIMPB_TYPE_MBDN;
- ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
- SIM_PHONEBOOK_INTERFACE, "read",
+ ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
+ CSD_SIMPB_INTERFACE, "ReadFirst",
phonebook_read_reply, &vmbx,
- DBUS_TYPE_BYTE, &pb_type,
- DBUS_TYPE_INT32, &location,
- DBUS_TYPE_BYTE, &location_type,
+ DBUS_TYPE_STRING, &pb_type,
DBUS_TYPE_INVALID);
if (ret < 0) {
- error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
- return FALSE;
+ error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
+ return;
}
-
- return FALSE;
-}
-
-static void csd_ready(DBusConnection *conn, void *user_data)
-{
- g_dbus_remove_watch(conn, csd_watch);
- csd_watch = 0;
-
- g_timeout_add_seconds(2, csd_init, NULL);
}
static inline DBusMessage *invalid_args(DBusMessage *msg)
@@ -1999,33 +1821,146 @@
g_str_equal(callerid_setting, "none")) {
save_callerid_to_file(callerid_setting);
callerid = get_callflag(callerid_setting);
- debug("telephony-maemo setting callerid flag: %s",
+ DBG("telephony-maemo6 setting callerid flag: %s",
callerid_setting);
return dbus_message_new_method_return(msg);
}
- error("telephony-maemo: invalid argument %s for method call"
+ error("telephony-maemo6: invalid argument %s for method call"
" SetCallerId", callerid_setting);
return invalid_args(msg);
}
+static DBusMessage *clear_lastnumber(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ g_free(last_dialed_number);
+ last_dialed_number = NULL;
+
+ return dbus_message_new_method_return(msg);
+}
+
static GDBusMethodTable telephony_maemo_methods[] = {
- {"SetCallerId", "s", "", set_callerid,
- G_DBUS_METHOD_FLAG_ASYNC},
+ { "SetCallerId", "s", "", set_callerid,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "ClearLastNumber", "", "", clear_lastnumber },
{ }
};
+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);
+}
+
+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, 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 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);
- csd_watch = g_dbus_add_service_watch(connection, CSD_CALL_BUS_NAME,
- csd_ready, NULL, NULL, NULL);
+ if (!dbus_connection_add_filter(connection, signal_filter,
+ NULL, NULL))
+ error("Can't add signal filter");
- if (dbus_bus_name_has_owner(connection, CSD_CALL_BUS_NAME, NULL))
- csd_ready(connection, NULL);
- else
- info("CSD not yet available. Waiting for it...");
+ 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=" CSD_CSNET_REGISTRATION,
+ NULL);
+ dbus_bus_add_match(connection,
+ "type=signal,interface=" CSD_CSNET_OPERATOR,
+ NULL);
+ dbus_bus_add_match(connection,
+ "type=signal,interface=" CSD_CSNET_SIGNAL,
+ 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();
@@ -2033,22 +1968,34 @@
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",
+ error("telephony-maemo6 interface %s init failed on path %s",
TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
}
- debug("telephony-maemo registering %s interface on path %s",
+ DBG("telephony-maemo6 registering %s interface on path %s",
TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
+ telephony_ready_ind(features, maemo_indicators, response_and_hold,
+ 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)
{
- if (csd_watch) {
- g_dbus_remove_watch(connection, csd_watch);
- csd_watch = 0;
- }
+ g_free(net.operator_name);
+ net.operator_name = NULL;
+
+ g_free(last_dialed_number);
+ last_dialed_number = NULL;
g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
g_slist_free(calls);
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 7c647b6..9c20112 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -2,9 +2,9 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2009 Intel Corporation
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -35,7 +35,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "telephony.h"
enum net_registration_status {
@@ -49,6 +49,7 @@
int status;
gboolean originating;
char *number;
+ guint watch;
};
static DBusConnection *connection = NULL;
@@ -63,6 +64,10 @@
#define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
#define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
+static guint registration_watch = 0;
+static guint voice_watch = 0;
+static guint device_watch = 0;
+
/* HAL battery namespace key values */
static int battchg_cur = -1; /* "battery.charge_level.current" */
static int battchg_last = -1; /* "battery.charge_level.last_full" */
@@ -131,20 +136,14 @@
return NULL;
}
-static inline DBusMessage *invalid_args(DBusMessage *msg)
-{
- return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
- "Invalid arguments in method call");
-}
-
void telephony_device_connected(void *telephony_device)
{
- debug("telephony-ofono: device %p connected", telephony_device);
+ DBG("telephony-ofono: device %p connected", telephony_device);
}
void telephony_device_disconnected(void *telephony_device)
{
- debug("telephony-ofono: device %p disconnected", telephony_device);
+ DBG("telephony-ofono: device %p disconnected", telephony_device);
events_enabled = FALSE;
}
@@ -166,7 +165,7 @@
void telephony_last_dialed_number_req(void *telephony_device)
{
- debug("telephony-ofono: last dialed number request");
+ DBG("telephony-ofono: last dialed number request");
if (last_dialed_number)
telephony_dial_number_req(telephony_device, last_dialed_number);
@@ -277,18 +276,25 @@
void telephony_dial_number_req(void *telephony_device, const char *number)
{
- char *clir = "default";
+ const char *clir;
int ret;
- debug("telephony-ofono: dial request to %s", number);
+ 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 = g_strdup("enabled");
+ clir = "enabled";
} else if (!strncmp(number, "#31#", 4)) {
number += 4;
- clir = g_strdup("disabled");
- }
+ clir = "disabled";
+ } else
+ clir = "default";
ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
OFONO_VCMANAGER_INTERFACE,
@@ -309,7 +315,13 @@
char *tone_string;
int ret;
- debug("telephony-ofono: transmit dtmf: %c", tone);
+ 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,
@@ -328,7 +340,7 @@
void telephony_subscriber_number_req(void *telephony_device)
{
- debug("telephony-ofono: subscriber number request");
+ DBG("telephony-ofono: subscriber number request");
if (subscriber_number)
telephony_subscriber_number_ind(subscriber_number,
@@ -342,7 +354,7 @@
GSList *l;
int i;
- debug("telephony-ofono: list current calls request");
+ DBG("telephony-ofono: list current calls request");
for (l = calls, i = 1; l != NULL; l = l->next, i++) {
struct voice_call *vc = l->data;
@@ -360,7 +372,7 @@
void telephony_operator_selection_req(void *telephony_device)
{
- debug("telephony-ofono: operator selection request");
+ DBG("telephony-ofono: operator selection request");
telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
net.operator_name ? net.operator_name : "");
@@ -369,13 +381,13 @@
void telephony_call_hold_req(void *telephony_device, const char *cmd)
{
- debug("telephony-ofono: got call hold request %s", cmd);
+ DBG("telephony-ofono: 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)
{
- debug("telephony-ofono: got %s NR and EC request",
+ DBG("telephony-ofono: got %s NR and EC request",
enable ? "enable" : "disable");
telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
@@ -383,10 +395,18 @@
void telephony_key_press_req(void *telephony_device, const char *keys)
{
- debug("telephony-ofono: got key press request for %s", keys);
+ DBG("telephony-ofono: got key press request for %s", keys);
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, ...)
{
@@ -417,12 +437,12 @@
static void handle_registration_property(const char *property, DBusMessageIter sub)
{
- char *status, *operator;
+ const char *status, *operator;
unsigned int signals_bar;
if (g_str_equal(property, "Status")) {
dbus_message_iter_get_basic(&sub, &status);
- debug("Status is %s", status);
+ DBG("Status is %s", status);
if (g_str_equal(status, "registered")) {
net.status = NETWORK_REG_STATUS_HOME;
telephony_update_indicator(ofono_indicators,
@@ -444,12 +464,12 @@
}
} else if (g_str_equal(property, "Operator")) {
dbus_message_iter_get_basic(&sub, &operator);
- debug("Operator is %s", 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(&sub, &signals_bar);
- debug("SignalStrength is %d", signals_bar);
+ DBG("SignalStrength is %d", signals_bar);
net.signals_bar = signals_bar;
telephony_update_indicator(ofono_indicators, "signal",
(signals_bar + 20) / 21);
@@ -478,7 +498,7 @@
dbus_message_iter_init(reply, &iter);
- /* ARRAY -> ENTRY -> VARIANT*/
+ /* ARRAY -> ENTRY -> VARIANT */
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
error("Unexpected signature in GetProperties return");
goto done;
@@ -523,6 +543,9 @@
static int get_registration_and_signal_status()
{
+ if (!modem_obj_path)
+ return -ENOENT;
+
return send_method_call(OFONO_BUS_NAME, modem_obj_path,
OFONO_NETWORKREG_INTERFACE,
"GetProperties", get_registration_reply,
@@ -537,7 +560,7 @@
char *property, *modem_obj_path_local;
int ret;
- debug("list_modem_reply is called\n");
+ DBG("list_modem_reply is called\n");
reply = dbus_pending_call_steal_reply(call);
dbus_error_init(&err);
@@ -575,8 +598,11 @@
dbus_message_iter_get_basic(&sub, &modem_obj_path_local);
modem_obj_path = g_strdup(modem_obj_path_local);
- debug("modem_obj_path is %p, %s\n", modem_obj_path,
- modem_obj_path);
+ if (modem_obj_path != NULL) {
+ DBG("modem_obj_path is %p, %s\n", modem_obj_path,
+ modem_obj_path);
+ break;
+ }
dbus_message_iter_next(&sub);
}
@@ -587,8 +613,8 @@
dbus_message_unref(reply);
}
-static void handle_networkregistration_property_changed(DBusMessage *msg,
- const char *call_path)
+static gboolean handle_registration_property_changed(DBusConnection *conn,
+ DBusMessage *msg, void *data)
{
DBusMessageIter iter, sub;
const char *property;
@@ -598,16 +624,18 @@
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
error("Unexpected signature in networkregistration"
" PropertyChanged signal");
- return;
+ return TRUE;
}
dbus_message_iter_get_basic(&iter, &property);
- debug("in handle_networkregistration_property_changed(),"
+ DBG("in handle_registration_property_changed(),"
" the property is %s", property);
dbus_message_iter_next(&iter);
dbus_message_iter_recurse(&iter, &sub);
handle_registration_property(property, sub);
+
+ return TRUE;
}
static void vc_getproperties_reply(DBusPendingCall *call, void *user_data)
@@ -618,7 +646,7 @@
const char *path = user_data;
struct voice_call *vc;
- debug("in vc_getproperties_reply");
+ DBG("in vc_getproperties_reply");
reply = dbus_pending_call_steal_reply(call);
dbus_error_init(&err);
@@ -627,7 +655,7 @@
err.name, err.message);
dbus_error_free(&err);
goto done;
- }
+ }
vc = find_vc(path);
if (!vc) {
@@ -640,28 +668,28 @@
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
error("Unexpected signature in vc_getproperties_reply()");
goto done;
- }
+ }
dbus_message_iter_recurse(&iter, &iter_entry);
if (dbus_message_iter_get_arg_type(&iter_entry)
- != DBUS_TYPE_DICT_ENTRY) {
+ != DBUS_TYPE_DICT_ENTRY) {
error("Unexpected signature in vc_getproperties_reply()");
goto done;
- }
+ }
while (dbus_message_iter_get_arg_type(&iter_entry)
- != DBUS_TYPE_INVALID) {
+ != DBUS_TYPE_INVALID) {
DBusMessageIter iter_property, sub;
char *property, *cli, *state;
dbus_message_iter_recurse(&iter_entry, &iter_property);
if (dbus_message_iter_get_arg_type(&iter_property)
- != DBUS_TYPE_STRING) {
+ != DBUS_TYPE_STRING) {
error("Unexpected signature in"
" vc_getproperties_reply()");
goto done;
- }
+ }
dbus_message_iter_get_basic(&iter_property, &property);
@@ -669,11 +697,11 @@
dbus_message_iter_recurse(&iter_property, &sub);
if (g_str_equal(property, "LineIdentification")) {
dbus_message_iter_get_basic(&sub, &cli);
- debug("in vc_getproperties_reply(), cli is %s", cli);
+ DBG("in vc_getproperties_reply(), cli is %s", cli);
vc->number = g_strdup(cli);
} else if (g_str_equal(property, "State")) {
dbus_message_iter_get_basic(&sub, &state);
- debug("in vc_getproperties_reply(),"
+ DBG("in vc_getproperties_reply(),"
" state is %s", state);
if (g_str_equal(state, "incoming"))
vc->status = CALL_STATUS_INCOMING;
@@ -713,7 +741,7 @@
EV_CALLSETUP_ALERTING);
break;
case CALL_STATUS_WAITING:
- debug("in CALL_STATUS_WAITING: case");
+ DBG("in CALL_STATUS_WAITING: case");
vc->originating = FALSE;
telephony_update_indicator(ofono_indicators, "callsetup",
EV_CALLSETUP_INCOMING);
@@ -724,96 +752,42 @@
dbus_message_unref(reply);
}
-static void handle_vcmanager_property_changed(DBusMessage *msg,
- const char *obj_path)
-{
- DBusMessageIter iter, sub, array;
- const char *property, *vc_obj_path = NULL;
- struct voice_call *vc = NULL, *vc_new = NULL;
-
- debug("in handle_vcmanager_property_changed");
-
- dbus_message_iter_init(msg, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
- error("Unexpected signature in vcmanager"
- " PropertyChanged signal");
- return;
- }
-
- dbus_message_iter_get_basic(&iter, &property);
- debug("in handle_vcmanager_property_changed(),"
- " the property is %s", property);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &sub);
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY) {
- error("Unexpected signature in vcmanager"
- " PropertyChanged signal");
- return;
- }
- dbus_message_iter_recurse(&sub, &array);
- while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
- dbus_message_iter_get_basic(&array, &vc_obj_path);
- vc = find_vc(vc_obj_path);
- if (vc) {
- debug("in handle_vcmanager_property_changed,"
- " found an existing vc");
- } else {
- vc_new = g_new0(struct voice_call, 1);
- vc_new->obj_path = g_strdup(vc_obj_path);
- calls = g_slist_append(calls, vc_new);
- }
- dbus_message_iter_next(&array);
- }
-
- if (!vc_new)
- return;
-
- send_method_call(OFONO_BUS_NAME, vc_new->obj_path,
- OFONO_VC_INTERFACE,
- "GetProperties", vc_getproperties_reply,
- vc_new->obj_path, DBUS_TYPE_INVALID);
-}
-
static void vc_free(struct voice_call *vc)
{
if (!vc)
return;
+ g_dbus_remove_watch(connection, vc->watch);
g_free(vc->obj_path);
g_free(vc->number);
g_free(vc);
}
-static void handle_vc_property_changed(DBusMessage *msg, const char *obj_path)
+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;
- struct voice_call *vc = NULL;
- debug("in handle_vc_property_changed, obj_path is %s", obj_path);
-
- vc = find_vc(obj_path);
-
- if (!vc)
- return;
+ DBG("in handle_vc_property_changed, obj_path is %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;
+ return TRUE;
}
dbus_message_iter_get_basic(&iter, &property);
- debug("in handle_vc_property_changed(), the property is %s", property);
+ DBG("in handle_vc_property_changed(), the property is %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);
- debug("in handle_vc_property_changed(), State is %s", state);
+ DBG("in handle_vc_property_changed(), State is %s", state);
if (g_str_equal(state, "disconnected")) {
printf("in disconnected case\n");
if (vc->status == CALL_STATUS_ACTIVE)
@@ -832,16 +806,15 @@
telephony_update_indicator(ofono_indicators,
"callsetup",
EV_CALLSETUP_INACTIVE);
- if (vc->status == CALL_STATUS_INCOMING) {
+ if (vc->status == CALL_STATUS_INCOMING)
telephony_calling_stopped_ind();
- }
vc->status = CALL_STATUS_ACTIVE;
- debug("vc status is CALL_STATUS_ACTIVE");
+ DBG("vc status is CALL_STATUS_ACTIVE");
} else if (g_str_equal(state, "alerting")) {
telephony_update_indicator(ofono_indicators,
- "callsetup", EV_CALLSETUP_ALERTING);
+ "callsetup", EV_CALLSETUP_ALERTING);
vc->status = CALL_STATUS_ALERTING;
- debug("vc status is CALL_STATUS_ALERTING");
+ DBG("vc status is CALL_STATUS_ALERTING");
} else if (g_str_equal(state, "incoming")) {
/* state change from waiting to incoming */
telephony_update_indicator(ofono_indicators,
@@ -849,9 +822,71 @@
telephony_incoming_call_ind(vc->number,
NUMBER_TYPE_TELEPHONY);
vc->status = CALL_STATUS_INCOMING;
- debug("vc status is CALL_STATUS_INCOMING");
+ DBG("vc status is CALL_STATUS_INCOMING");
}
}
+
+ return TRUE;
+}
+
+static gboolean handle_vcmanager_property_changed(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, sub, array;
+ const char *property, *vc_obj_path = NULL;
+ struct voice_call *vc, *vc_new = NULL;
+
+ DBG("in handle_vcmanager_property_changed");
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+ error("Unexpected signature in vcmanager"
+ " PropertyChanged signal");
+ return TRUE;
+ }
+
+ dbus_message_iter_get_basic(&iter, &property);
+ DBG("in handle_vcmanager_property_changed(),"
+ " the property is %s", property);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &sub);
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY) {
+ error("Unexpected signature in vcmanager"
+ " PropertyChanged signal");
+ return TRUE;
+ }
+ dbus_message_iter_recurse(&sub, &array);
+ while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
+ dbus_message_iter_get_basic(&array, &vc_obj_path);
+ vc = find_vc(vc_obj_path);
+ if (vc) {
+ DBG("in handle_vcmanager_property_changed,"
+ " found an existing vc");
+ } else {
+ vc_new = g_new0(struct voice_call, 1);
+ vc_new->obj_path = g_strdup(vc_obj_path);
+ calls = g_slist_append(calls, vc_new);
+ vc_new->watch = g_dbus_add_signal_watch(connection,
+ NULL, vc_obj_path,
+ OFONO_VC_INTERFACE,
+ "PropertyChanged",
+ handle_vc_property_changed,
+ vc_new, NULL);
+ }
+ dbus_message_iter_next(&array);
+ }
+
+ if (!vc_new)
+ return TRUE;
+
+ send_method_call(OFONO_BUS_NAME, vc_new->obj_path,
+ OFONO_VC_INTERFACE,
+ "GetProperties", vc_getproperties_reply,
+ vc_new->obj_path, DBUS_TYPE_INVALID);
+
+ return TRUE;
}
static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
@@ -871,20 +906,26 @@
goto done;
}
- dbus_message_get_args(reply, NULL,
+ dbus_error_init(&err);
+ if (dbus_message_get_args(reply, &err,
DBUS_TYPE_INT32, &level,
- DBUS_TYPE_INVALID);
+ 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)
- debug("telephony-ofono: battery.charge_level.last_full"
+ DBG("telephony-ofono: battery.charge_level.last_full"
" is %d", *value);
else if (value == &battchg_design)
- debug("telephony-ofono: battery.charge_level.design"
+ DBG("telephony-ofono: battery.charge_level.design"
" is %d", *value);
else
- debug("telephony-ofono: battery.charge_level.current"
+ DBG("telephony-ofono: battery.charge_level.current"
" is %d", *value);
if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
@@ -913,62 +954,8 @@
DBUS_TYPE_INVALID);
}
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *reply;
- DBusError err;
- DBusMessageIter iter, sub;
- int type;
- const char *path;
- char match_string[256];
-
- debug("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);
-
- debug("telephony-ofono: 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 handle_hal_property_modified(DBusMessage *msg)
+static gboolean handle_hal_property_modified(DBusConnection *conn,
+ DBusMessage *msg, void *data)
{
const char *path;
DBusMessageIter iter, array;
@@ -980,7 +967,7 @@
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
error("Unexpected signature in hal PropertyModified signal");
- return;
+ return TRUE;
}
dbus_message_iter_get_basic(&iter, &num_changes);
@@ -988,7 +975,7 @@
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
error("Unexpected signature in hal PropertyModified signal");
- return;
+ return TRUE;
}
dbus_message_iter_recurse(&iter, &array);
@@ -1018,58 +1005,81 @@
dbus_message_iter_next(&array);
}
+
+ return TRUE;
}
-static DBusHandlerResult signal_filter(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
{
- const char *path = dbus_message_get_path(msg);
+ DBusMessage *reply;
+ DBusError err;
+ DBusMessageIter iter, sub;
+ int type;
+ const char *path;
- if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ DBG("begin of hal_find_device_reply()");
+ reply = dbus_pending_call_steal_reply(call);
- if (dbus_message_is_signal(msg, OFONO_NETWORKREG_INTERFACE,
- "PropertyChanged"))
- handle_networkregistration_property_changed(msg, path);
- else if (dbus_message_is_signal(msg, OFONO_VCMANAGER_INTERFACE,
- "PropertyChanged"))
- handle_vcmanager_property_changed(msg, path);
- else if (dbus_message_is_signal(msg, OFONO_VC_INTERFACE,
- "PropertyChanged"))
- handle_vc_property_changed(msg, path);
- else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
- "PropertyModified"))
- handle_hal_property_modified(msg);
+ dbus_error_init(&err);
- debug("signal_filter is called, path is %s\n", path);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ 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);
+
+ device_watch = g_dbus_add_signal_watch(connection, NULL, path,
+ "org.freedesktop.Hal.Device",
+ "PropertyModified",
+ handle_hal_property_modified,
+ NULL, 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);
}
int telephony_init(void)
{
const char *battery_cap = "battery";
- char match_string[128];
int ret;
connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
- if (!dbus_connection_add_filter(connection, signal_filter,
- NULL, NULL)) {
- error("telephony-ofono: Can't add signal filter");
- return -EIO;
- }
+ registration_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_NETWORKREG_INTERFACE,
+ "PropertyChanged",
+ handle_registration_property_changed,
+ NULL, NULL);
- snprintf(match_string, sizeof(match_string), "type=signal,interface=%s",
- OFONO_NETWORKREG_INTERFACE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string), "type=signal,interface=%s",
- OFONO_VCMANAGER_INTERFACE);
- dbus_bus_add_match(connection, match_string, NULL);
-
- snprintf(match_string, sizeof(match_string), "type=signal,interface=%s",
- OFONO_VC_INTERFACE);
- dbus_bus_add_match(connection, match_string, NULL);
+ voice_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_VCMANAGER_INTERFACE,
+ "PropertyChanged",
+ handle_vcmanager_property_changed,
+ NULL, NULL);
ret = send_method_call(OFONO_BUS_NAME, OFONO_PATH,
OFONO_MANAGER_INTERFACE, "GetProperties",
@@ -1087,7 +1097,7 @@
if (ret < 0)
return ret;
- debug("telephony_init() successfully");
+ DBG("telephony_init() successfully");
return ret;
}
@@ -1103,7 +1113,9 @@
g_slist_free(calls);
calls = NULL;
- dbus_connection_remove_filter(connection, signal_filter, NULL);
+ g_dbus_remove_watch(connection, registration_watch);
+ g_dbus_remove_watch(connection, voice_watch);
+ g_dbus_remove_watch(connection, device_watch);
dbus_connection_unref(connection);
connection = NULL;
diff --git a/audio/telephony.h b/audio/telephony.h
index 9bc5ee2..5343e8c 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -155,6 +155,7 @@
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 */
@@ -170,6 +171,7 @@
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 */
@@ -205,10 +207,10 @@
if (!ind)
return -ENOENT;
- debug("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
+ DBG("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
if (ind->ignore_redundant && ind->val == new_val) {
- debug("Ignoring no-change indication");
+ DBG("Ignoring no-change indication");
return 0;
}
diff --git a/audio/unix.c b/audio/unix.c
index b04cc59..cf2704c 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -39,7 +39,7 @@
#include <dbus/dbus.h>
#include <glib.h>
-#include "logging.h"
+#include "log.h"
#include "ipc.h"
#include "device.h"
#include "manager.h"
@@ -97,7 +97,7 @@
static void client_free(struct unix_client *client)
{
- debug("client_free(%p)", client);
+ DBG("client_free(%p)", client);
if (client->cancel && client->dev && client->req_id > 0)
client->cancel(client->dev, client->req_id);
@@ -147,7 +147,7 @@
const char *type = bt_audio_strtype(msg->type);
const char *name = bt_audio_strname(msg->name);
- debug("Audio API: %s -> %s", type, name);
+ DBG("Audio API: %s -> %s", type, name);
if (send(client->sock, msg, msg->length, 0) < 0)
error("Error %s(%d)", strerror(errno), errno);
@@ -168,6 +168,7 @@
rsp->posix_errno = err;
+ DBG("sending error %s(%d)", strerror(err), err);
unix_ipc_sendmsg(client, &rsp->h);
}
@@ -176,13 +177,20 @@
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_SINK_INTERFACE) && dev->sink)
+ } 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;
@@ -310,14 +318,14 @@
unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}
-static void gateway_setup_complete(struct audio_device *dev, void *user_data)
+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 (!dev) {
- unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
+ if (err) {
+ unix_ipc_error(client, BT_SET_CONFIGURATION, err->code);
return;
}
@@ -380,13 +388,18 @@
unix_ipc_error(client, BT_START_STREAM, EIO);
}
-static void gateway_resume_complete(struct audio_device *dev, void *user_data)
+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;
@@ -435,7 +448,7 @@
static void print_mpeg12(struct mpeg_codec_cap *mpeg)
{
- debug("Media Codec: MPEG12"
+ DBG("Media Codec: MPEG12"
" Channel Modes: %s%s%s%s"
" Frequencies: %s%s%s%s%s%s"
" Layers: %s%s%s"
@@ -460,7 +473,7 @@
static void print_sbc(struct sbc_codec_cap *sbc)
{
- debug("Media Codec: SBC"
+ DBG("Media Codec: SBC"
" Channel Modes: %s%s%s%s"
" Frequencies: %s%s%s%s"
" Subbands: %s%s"
@@ -487,6 +500,7 @@
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)
{
@@ -507,6 +521,13 @@
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;
@@ -518,7 +539,6 @@
sbc->max_bitpool = sbc_cap->max_bitpool;
print_sbc(sbc_cap);
- codec->type = BT_A2DP_SBC_SINK;
} 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;
@@ -526,6 +546,13 @@
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;
@@ -536,7 +563,6 @@
mpeg->bitrate = mpeg_cap->bitrate;
print_mpeg12(mpeg_cap);
- codec->type = BT_A2DP_MPEG12_SINK;
} else {
size_t codec_length, type_length, total_length;
@@ -549,11 +575,17 @@
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->type = BT_A2DP_UNKNOWN_SINK;
}
codec->seid = seid;
@@ -561,7 +593,7 @@
codec->lock = lock;
rsp->h.length += codec->length;
- debug("Append %s seid %d - length %d - total %d",
+ DBG("Append %s seid %d - length %d - total %d",
configured ? "configured" : "", seid, codec->length,
rsp->h.length);
@@ -579,7 +611,7 @@
GSList *l;
if (!g_slist_find(clients, client)) {
- debug("Client disconnected during discovery");
+ DBG("Client disconnected during discovery");
return;
}
@@ -606,7 +638,8 @@
type = avdtp_get_type(rsep);
- if (type != AVDTP_SEP_TYPE_SINK)
+ if (type != AVDTP_SEP_TYPE_SINK &&
+ type != AVDTP_SEP_TYPE_SOURCE)
continue;
cap = avdtp_get_codec(rsep);
@@ -630,8 +663,7 @@
struct unix_client *c = cl->data;
struct a2dp_data *ca2dp = &c->d.a2dp;
- if (ca2dp && ca2dp->session == session &&
- c->seid == seid) {
+ if (ca2dp->session == session && c->seid == seid) {
lock = c->lock;
break;
}
@@ -641,7 +673,7 @@
if (sep && a2dp_sep_get_lock(sep))
lock = BT_WRITE_LOCK;
- a2dp_append_codec(rsp, cap, seid, configured, lock);
+ a2dp_append_codec(rsp, cap, seid, type, configured, lock);
}
unix_ipc_sendmsg(client, &rsp->h);
@@ -819,6 +851,7 @@
switch (client->type) {
case TYPE_SINK:
+ case TYPE_SOURCE:
a2dp = &client->d.a2dp;
if (!a2dp->session)
@@ -875,8 +908,6 @@
strncpy(rsp->object, dev->path, sizeof(rsp->object));
unix_ipc_sendmsg(client, &rsp->h);
-
- return;
}
static void start_open(struct audio_device *dev, struct unix_client *client)
@@ -1254,6 +1285,7 @@
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)) {
@@ -1264,29 +1296,33 @@
str2ba(req->source, &src);
str2ba(req->destination, &dst);
- if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
- client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
- else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
- client->interface = g_strdup(AUDIO_SINK_INTERFACE);
-
if (!manager_find_device(req->object, &src, &dst, NULL, FALSE))
goto failed;
- dev = manager_find_device(req->object, &src, &dst, client->interface,
- TRUE);
+ 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,
- client->interface, FALSE);
+ interface, FALSE);
- if (!dev && req->transport == BT_CAPABILITIES_TRANSPORT_SCO) {
- g_free(client->interface);
- client->interface = g_strdup(AUDIO_GATEWAY_INTERFACE);
-
+ 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,
- client->interface, TRUE);
+ interface, TRUE);
if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
dev = manager_find_device(req->object, &src, &dst,
- client->interface, FALSE);
+ interface, FALSE);
}
if (!dev) {
@@ -1294,12 +1330,17 @@
goto failed;
}
- client->type = select_service(dev, client->interface);
+ 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);
@@ -1318,7 +1359,7 @@
!g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE))
return -EIO;
- debug("open sco - object=%s source=%s destination=%s lock=%s%s",
+ 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",
@@ -1331,11 +1372,13 @@
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))
+ else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) &&
+ !g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE))
return -EIO;
- debug("open a2dp - object=%s source=%s destination=%s lock=%s%s",
+ 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",
@@ -1424,8 +1467,10 @@
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))
+ else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) &&
+ !g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE))
return -EIO;
if (client->caps) {
@@ -1439,7 +1484,8 @@
client->caps = g_slist_append(client->caps, media_transport);
- if (req->codec.type == BT_A2DP_MPEG12_SINK) {
+ 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));
@@ -1457,7 +1503,8 @@
sizeof(mpeg_cap));
print_mpeg12(&mpeg_cap);
- } else if (req->codec.type == BT_A2DP_SBC_SINK) {
+ } 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));
@@ -1491,7 +1538,7 @@
if (req->codec.seid != client->seid) {
error("Unable to set configuration: seid %d not opened",
- client->seid);
+ req->codec.seid);
goto failed;
}
@@ -1577,6 +1624,56 @@
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];
@@ -1589,7 +1686,7 @@
return FALSE;
if (cond & (G_IO_HUP | G_IO_ERR)) {
- debug("Unix client disconnected (fd=%d)", client->sock);
+ DBG("Unix client disconnected (fd=%d)", client->sock);
goto failed;
}
@@ -1605,7 +1702,7 @@
type = bt_audio_strtype(msghdr->type);
name = bt_audio_strname(msghdr->name);
- debug("Audio API: %s <- %s", type, name);
+ DBG("Audio API: %s <- %s", type, name);
if (msghdr->length != len) {
error("Invalid message: length mismatch");
@@ -1641,6 +1738,10 @@
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);
@@ -1682,7 +1783,7 @@
return TRUE;
}
- debug("Accepted new client connection on unix socket (fd=%d)", cli_sk);
+ DBG("Accepted new client connection on unix socket (fd=%d)", cli_sk);
set_nonblocking(cli_sk);
client = g_new0(struct unix_client, 1);
@@ -1701,7 +1802,7 @@
{
GSList *l;
- debug("unix_device_removed(%p)", dev);
+ DBG("unix_device_removed(%p)", dev);
l = clients;
while (l) {
@@ -1717,6 +1818,29 @@
}
}
+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;
@@ -1756,7 +1880,7 @@
server_cb, NULL);
g_io_channel_unref(io);
- debug("Unix socket created: %d", sk);
+ DBG("Unix socket created: %d", sk);
return 0;
}
diff --git a/audio/unix.h b/audio/unix.h
index 12cf3ef..74ca16d 100644
--- a/audio/unix.h
+++ b/audio/unix.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -24,5 +24,7 @@
void unix_device_removed(struct audio_device *dev);
+void unix_delay_report(struct audio_device *dev, uint8_t seid, uint16_t delay);
+
int unix_init(void);
void unix_exit(void);
diff --git a/bluez.m4 b/bluez.m4
deleted file mode 100644
index 0257a3f..0000000
--- a/bluez.m4
+++ /dev/null
@@ -1,40 +0,0 @@
-AC_DEFUN([AM_PATH_BLUEZ], [
- if (test "${prefix}" = "NONE"); then
- bluez_prefix=${ac_default_prefix}
- else
- bluez_prefix=${prefix}
- fi
-
- AC_ARG_WITH(bluez, AC_HELP_STRING([--with-bluez=DIR], [BlueZ library is installed in DIR]), [
- if (test "${withval}" != "yes"); then
- bluez_prefix=${withval}
- fi
- ])
-
- ac_save_CPPFLAGS=$CPPFLAGS
- ac_save_LDFLAGS=$LDFLAGS
-
- BLUEZ_CFLAGS=""
- test -d "${bluez_prefix}/include" && BLUEZ_CFLAGS="$BLUEZ_CFLAGS -I${bluez_prefix}/include"
-
- CPPFLAGS="$CPPFLAGS $BLUEZ_CFLAGS"
- AC_CHECK_HEADER(bluetooth/bluetooth.h,, AC_MSG_ERROR(Bluetooth header files not found))
-
- BLUEZ_LIBS=""
- if (test "${ac_default_prefix}" = "${bluez_prefix}"); then
- test -d "${libdir}" && BLUEZ_LIBS="$BLUEZ_LIBS -L${libdir}"
- else
- test -d "${bluez_prefix}/lib64" && BLUEZ_LIBS="$BLUEZ_LIBS -L${bluez_prefix}/lib64"
- test -d "${bluez_prefix}/lib" && BLUEZ_LIBS="$BLUEZ_LIBS -L${bluez_prefix}/lib"
- fi
-
- LDFLAGS="$LDFLAGS $BLUEZ_LIBS"
- AC_CHECK_LIB(bluetooth, hci_open_dev, BLUEZ_LIBS="$BLUEZ_LIBS -lbluetooth", AC_MSG_ERROR(Bluetooth library not found))
- AC_CHECK_LIB(bluetooth, sdp_connect,, AC_CHECK_LIB(sdp, sdp_connect, BLUEZ_LIBS="$BLUEZ_LIBS -lsdp"))
-
- CPPFLAGS=$ac_save_CPPFLAGS
- LDFLAGS=$ac_save_LDFLAGS
-
- AC_SUBST(BLUEZ_CFLAGS)
- AC_SUBST(BLUEZ_LIBS)
-])
diff --git a/bootstrap-configure b/bootstrap-configure
index 15b3ba7..7456103 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -17,6 +17,8 @@
--localstatedir=/var \
--libexecdir=/lib \
--enable-netlink \
+ --enable-capng \
+ --enable-tracer \
--enable-tools \
--enable-bccmd \
--enable-dfutool \
@@ -27,6 +29,5 @@
--enable-test \
--enable-cups \
--disable-pcmcia \
- --disable-manpages \
--disable-udevrules \
--disable-configfiles $*
diff --git a/client/Makefile.am b/client/Makefile.am
deleted file mode 100644
index 0274292..0000000
--- a/client/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/common/Android.mk b/common/Android.mk
deleted file mode 100755
index 74c0bec..0000000
--- a/common/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- btio.c \
- glib-helper.c \
- logging.c \
- oui.c \
- sdp-xml.c \
- textfile.c \
- test_textfile.c \
- android_bluez.c
-
-LOCAL_CFLAGS+= \
- -O3 \
- -DNEED_DBUS_WATCH_GET_UNIX_FD
-
-ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
-LOCAL_CFLAGS += \
- -DBOARD_HAVE_BLUETOOTH_BCM
-endif
-
-LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(call include-path-for, glib) \
- $(call include-path-for, glib)/glib \
- $(call include-path-for, dbus)
-
-LOCAL_MODULE:=libbluez-common-static
-
-LOCAL_STATIC_LIBRARY:= \
- libglib_static
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/common/Makefile.am b/common/Makefile.am
deleted file mode 100644
index 8fe1547..0000000
--- a/common/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-
-noinst_LIBRARIES = libhelper.a
-
-libhelper_a_SOURCES = oui.h oui.c textfile.h textfile.c logging.h logging.c \
- glib-helper.h glib-helper.c sdp-xml.h sdp-xml.c btio.h btio.c
-
-noinst_PROGRAMS = test_textfile
-
-test_textfile_LDADD = libhelper.a
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-EXTRA_DIST = ppoll.h uinput.h
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/common/logging.c b/common/logging.c
deleted file mode 100644
index 6c6f925..0000000
--- a/common/logging.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * 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 <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-
-#include "logging.h"
-
-static volatile int debug_enabled = 0;
-
-static inline void vinfo(const char *format, va_list ap)
-{
- vsyslog(LOG_INFO, format, ap);
-}
-
-void info(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
-
- vinfo(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 debug(const char *format, ...)
-{
- va_list ap;
-
- if (!debug_enabled)
- return;
-
- va_start(ap, format);
-
- vsyslog(LOG_DEBUG, format, ap);
-
- va_end(ap);
-}
-
-void toggle_debug(void)
-{
- debug_enabled = (debug_enabled + 1) % 2;
-}
-
-void enable_debug(void)
-{
- debug_enabled = 1;
-}
-
-void disable_debug(void)
-{
- debug_enabled = 0;
-}
-
-void start_logging(const char *ident, const char *message, ...)
-{
- va_list ap;
-
- openlog(ident, LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-
- va_start(ap, message);
-
- vinfo(message, ap);
-
- va_end(ap);
-}
-
-void stop_logging(void)
-{
- closelog();
-}
diff --git a/common/logging.h b/common/logging.h
deleted file mode 100644
index 9508733..0000000
--- a/common/logging.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * 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
- *
- */
-
-#ifndef __LOGGING_H
-#define __LOGGING_H
-
-void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void toggle_debug(void);
-void enable_debug(void);
-void disable_debug(void);
-void start_logging(const char *ident, const char *message, ...);
-void stop_logging(void);
-
-#define DBG(fmt, arg...) debug("%s: " fmt "\n" , __FUNCTION__ , ## arg)
-
-#endif /* __LOGGING_H */
diff --git a/compat/Android.mk b/compat/Android.mk
index 3de66b4..2f99d65 100755
--- a/compat/Android.mk
+++ b/compat/Android.mk
@@ -13,17 +13,16 @@
pand.c bnep.c sdp.c
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" -DSTORAGEDIR=\"/data/misc/bluetoothd\" -DNEED_PPOLL -D__ANDROID__
+ -DVERSION=\"4.69\" -DSTORAGEDIR=\"/data/misc/bluetoothd\" -DNEED_PPOLL -D__ANDROID__
LOCAL_C_INCLUDES:=\
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
LOCAL_SHARED_LIBRARIES := \
- libbluetooth libcutils
-
-LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static
+ libbluetoothd \
+ libbluetooth \
+ libcutils
LOCAL_MODULE_TAGS :=
LOCAL_MODULE:=pand
diff --git a/compat/Makefile.am b/compat/Makefile.am
deleted file mode 100644
index 58254ad..0000000
--- a/compat/Makefile.am
+++ /dev/null
@@ -1,47 +0,0 @@
-
-bin_PROGRAMS =
-man_MANS =
-
-if HIDD
-bin_PROGRAMS += hidd
-
-hidd_SOURCES = hidd.c hidd.h sdp.h sdp.c fakehid.c
-
-hidd_LDADD = $(top_builddir)/common/libhelper.a @BLUEZ_LIBS@ -lm
-
-if MANPAGES
-man_MANS += hidd.1
-endif
-endif
-
-if PAND
-bin_PROGRAMS += pand
-
-pand_SOURCES = pand.c pand.h bnep.c sdp.h sdp.c
-
-pand_LDADD = $(top_builddir)/common/libhelper.a @BLUEZ_LIBS@
-
-if MANPAGES
-man_MANS += pand.1
-endif
-endif
-
-if DUND
-bin_PROGRAMS += dund
-
-dund_SOURCES = dund.c dund.h lib.h sdp.h sdp.c dun.c msdun.c
-
-dund_LDADD = $(top_builddir)/common/libhelper.a @BLUEZ_LIBS@
-
-if MANPAGES
-man_MANS += dund.1
-endif
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-EXTRA_DIST = fakehid.txt hidd.1 pand.1 dund.1
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/compat/bnep.c b/compat/bnep.c
index 0498c78..2e4fb9d 100644
--- a/compat/bnep.c
+++ b/compat/bnep.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -93,7 +93,7 @@
}
/* Temporary ioctl compatibility hack */
- {
+ {
struct bnep_connlist_req req;
struct bnep_conninfo ci[1];
@@ -194,19 +194,19 @@
return 0;
}
-struct __service_16 {
+struct __service_16 {
uint16_t dst;
uint16_t src;
} __attribute__ ((packed));
-struct __service_32 {
+struct __service_32 {
uint16_t unused1;
uint16_t dst;
uint16_t unused2;
uint16_t src;
} __attribute__ ((packed));
-struct __service_128 {
+struct __service_128 {
uint16_t unused1;
uint16_t dst;
uint16_t unused2[8];
@@ -246,7 +246,7 @@
return bnep_connadd(sk, role, dev);
}
-/* Create BNEP connection
+/* Create BNEP connection
* sk - Connect L2CAP socket
* role - Local role
* service - Remote service
diff --git a/compat/dun.c b/compat/dun.c
index c74e5ee..59f036f 100644
--- a/compat/dun.c
+++ b/compat/dun.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -86,6 +86,7 @@
}
close(sk);
+ free(dl);
return r;
}
@@ -106,8 +107,10 @@
int len = readlink(de->d_name, link, sizeof(link));
if (len > 0) {
link[len] = 0;
- if (strstr(link, dev))
+ if (strstr(link, dev)) {
+ closedir(dir);
return 1;
+ }
}
}
@@ -155,7 +158,7 @@
{
int pid = fork();
int fd;
-
+
switch (pid) {
case -1:
return -1;
@@ -241,7 +244,7 @@
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)) &&
diff --git a/compat/dund.c b/compat/dund.c
index fc8ba30..af1b536 100644
--- a/compat/dund.c
+++ b/compat/dund.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -192,7 +192,7 @@
}
ba2str(&sa.rc_bdaddr, ba);
- sprintf(ch, "%d", channel);
+ snprintf(ch, sizeof(ch), "%d", channel);
/* Setup environment */
setenv("DUN_BDADDR", ba, 1);
@@ -247,7 +247,7 @@
sa.rc_bdaddr = src_addr;
if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)))
- syslog(LOG_ERR, "Bind failed. %s(%d)",
+ syslog(LOG_ERR, "Bind failed. %s(%d)",
strerror(errno), errno);
sa.rc_channel = ch;
@@ -337,7 +337,7 @@
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;
@@ -405,7 +405,7 @@
static const char *main_sopts = "hsc:k:Kr:i:lnp::DQ::AESMP:C::P:Xam:u";
-static const char *main_help =
+static const char *main_help =
"Bluetooth LAP (LAN Access over PPP) daemon version %s\n"
"Usage:\n"
"\tdund <options> [pppd options]\n"
@@ -568,21 +568,26 @@
io_init();
- if (dun_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;
}
@@ -612,6 +617,7 @@
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;
}
}
@@ -634,5 +640,6 @@
break;
}
+ free(dst);
return 0;
}
diff --git a/compat/dund.h b/compat/dund.h
index 0408e09..e3a4ef6 100644
--- a/compat/dund.h
+++ b/compat/dund.h
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/compat/fakehid.c b/compat/fakehid.c
index 438185d..b996d10 100644
--- a/compat/fakehid.c
+++ b/compat/fakehid.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/compat/hidd.c b/compat/hidd.c
index 212c092..88944cf 100644
--- a/compat/hidd.c
+++ b/compat/hidd.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -453,6 +453,7 @@
int csk, isk, err;
memset(&req, 0, sizeof(req));
+ name[0] = '\0';
err = get_sdp_device_info(src, dst, &req);
if (err < 0 && fakehid)
@@ -572,7 +573,7 @@
for (i = 0; i < num_rsp; i++) {
memcpy(class, (info+i)->dev_class, 3);
- if ((class[0] == 0x00 && class[2] == 0x00 &&
+ 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);
diff --git a/compat/hidd.h b/compat/hidd.h
index 362815a..0536967 100644
--- a/compat/hidd.h
+++ b/compat/hidd.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/compat/lib.h b/compat/lib.h
index d6373a7..3b3aeb5 100644
--- a/compat/lib.h
+++ b/compat/lib.h
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/compat/msdun.c b/compat/msdun.c
index 1759ef6..ae88c0c 100644
--- a/compat/msdun.c
+++ b/compat/msdun.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -58,7 +58,7 @@
char buf[40];
unsigned len = 0;
int r;
-
+
while (1) {
r = read(fd, buf + len, sizeof(buf) - len - 1);
if (r < 0) {
@@ -92,7 +92,7 @@
write_n(fd, "CLIENTSERVER", 12);
case MS_PPP:
return MS_SUCCESS;
- default:
+ default:
return MS_FAILED;
}
}
@@ -123,7 +123,7 @@
alarm(0);
signal(SIGALRM, osig);
-
+
switch (r) {
case MS_SUCCESS:
case MS_PPP:
@@ -142,7 +142,7 @@
}
alarm(timeout);
-
+
if (server)
r = ms_server(fd);
else
diff --git a/compat/pand.c b/compat/pand.c
index 747661f..6554e50 100644
--- a/compat/pand.c
+++ b/compat/pand.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -367,7 +367,7 @@
bacpy(&l2a.l2_bdaddr, bdaddr);
l2a.l2_psm = htobs(BNEP_PSM);
- if (!connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) &&
+ if (!connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) &&
!bnep_create_connection(sk, role, service, netdev)) {
syslog(LOG_INFO, "%s connected", netdev);
@@ -454,7 +454,7 @@
ba2str(&ii[i].bdaddr, dst);
if (use_sdp) {
- syslog(LOG_INFO, "Searching for %s on %s",
+ syslog(LOG_INFO, "Searching for %s on %s",
bnep_svc2str(service), dst);
if (bnep_sdp_search(&src_addr, &ii[i].bdaddr, service) <= 0)
@@ -512,7 +512,7 @@
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
@@ -595,7 +595,7 @@
static const char *main_sopts = "hsc:k:Kr:d:e:i:lnp::DQ::AESMC::P:u:o:z";
-static const char *main_help =
+static const char *main_help =
"Bluetooth PAN daemon version %s\n"
"Usage:\n"
"\tpand <options>\n"
@@ -745,21 +745,26 @@
argv += optind;
optind = 0;
- if (bnep_init())
+ 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;
}
@@ -790,12 +795,15 @@
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())
+ if (pidfile && write_pidfile()) {
+ free(dst);
return -1;
+ }
if (dst) {
/* Disable cache invalidation */
diff --git a/compat/pand.h b/compat/pand.h
index 4819178..08b5bdc 100644
--- a/compat/pand.h
+++ b/compat/pand.h
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/compat/sdp.c b/compat/sdp.c
index d411c05..8898136 100644
--- a/compat/sdp.c
+++ b/compat/sdp.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -368,7 +368,7 @@
return -EIO;
}
-void bnep_sdp_unregister(void)
+void bnep_sdp_unregister(void)
{
if (record && sdp_record_unregister(session, record))
syslog(LOG_ERR, "Service record unregistration failed.");
@@ -424,7 +424,7 @@
/* Supported protocols */
{
- uint16_t ptype[4] = {
+ uint16_t ptype[4] = {
0x0800, /* IPv4 */
0x0806, /* ARP */
};
@@ -483,7 +483,7 @@
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;
@@ -558,7 +558,7 @@
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)
+void dun_sdp_unregister(void)
{
if (record && sdp_record_unregister(session, record))
syslog(LOG_ERR, "Service record unregistration failed.");
@@ -575,7 +575,7 @@
session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
if (!session) {
- syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
+ syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
strerror(errno), errno);
return -1;
}
@@ -670,7 +670,7 @@
s = sdp_connect(src, dst, 0);
if (!s) {
- syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
+ syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
strerror(errno), errno);
return -1;
}
diff --git a/compat/sdp.h b/compat/sdp.h
index bec58a2..6ca975f 100644
--- a/compat/sdp.h
+++ b/compat/sdp.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/configure.ac b/configure.ac
index 85e1dae..b004f6e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
AC_PREREQ(2.60)
-AC_INIT()
+AC_INIT(bluez, 4.69)
-AM_INIT_AUTOMAKE(bluez, 4.47)
+AM_INIT_AUTOMAKE([foreign subdir-objects])
AM_CONFIG_HEADER(config.h)
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -17,10 +17,12 @@
AC_LANG_C
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
m4_define([_LT_AC_TAGCONFIG], [])
m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
@@ -28,8 +30,6 @@
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
-GTK_DOC_CHECK
-
AC_FUNC_PPOLL
AC_CHECK_LIB(dl, dlopen, dummy=yes,
@@ -40,35 +40,29 @@
AC_PATH_ALSA
AC_PATH_GSTREAMER
AC_PATH_USB
-AC_PATH_NETLINK
AC_PATH_SNDFILE
AC_ARG_BLUEZ
-AC_OUTPUT([
- Makefile
- include/Makefile
- lib/Makefile
- gdbus/Makefile
- common/Makefile
- sbc/Makefile
- src/Makefile
- test/Makefile
- cups/Makefile
- tools/Makefile
- client/Makefile
- rfcomm/Makefile
- compat/Makefile
- plugins/Makefile
- network/Makefile
- serial/Makefile
- input/Makefile
- audio/Makefile
- scripts/Makefile
- scripts/bluetooth.rules
- doc/Makefile
- doc/version.xml
- src/bluetoothd.8
- src/hcid.conf.5
- bluez.pc
-])
+AC_ARG_ENABLE(capng, AC_HELP_STRING([--enable-capng],
+ [enable capabilities support]), [enable_capng=${enableval}])
+if (test "${enable_capng}" = "yes"); then
+ PKG_CHECK_MODULES(CAPNG, libcap-ng, dummy=yes,
+ AC_MSG_ERROR(Capabilities library is required))
+ AC_SUBST(CAPNG_CFLAGS)
+ AC_SUBST(CAPNG_LIBS)
+ AC_DEFINE(HAVE_CAPNG, 1, [Define to 1 if you have capabilities library.])
+fi
+
+AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink],
+ [enable netlink support]), [enable_netlink=${enableval}])
+if (test "${enable_netlink}" = "yes"); then
+ PKG_CHECK_MODULES(NETLINK, libnl-1, dummy=yes,
+ AC_MSG_ERROR(Netlink library is required))
+ AC_SUBST(NETLINK_CFLAGS)
+ AC_SUBST(NETLINK_LIBS)
+fi
+AM_CONDITIONAL(NETLINK, test "${enable_netlink}" = "yes")
+
+AC_OUTPUT(Makefile scripts/bluetooth.rules doc/version.xml
+ src/bluetoothd.8 bluez.pc)
diff --git a/cups/Makefile.am b/cups/Makefile.am
deleted file mode 100644
index 70a8ba8..0000000
--- a/cups/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-
-if CUPS
-cupsdir = $(libdir)/cups/backend
-
-cups_PROGRAMS = bluetooth
-
-bluetooth_SOURCES = main.c cups.h sdp.c spp.c hcrp.c
-
-bluetooth_LDADD = @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/cups/cups.h b/cups/cups.h
index 2cbac98..f4e0c01 100644
--- a/cups/cups.h
+++ b/cups/cups.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/cups/hcrp.c b/cups/hcrp.c
index 155236d..7aafcdc 100644
--- a/cups/hcrp.c
+++ b/cups/hcrp.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/cups/main.c b/cups/main.c
index 2fbfe7e..9659a11 100644
--- a/cups/main.c
+++ b/cups/main.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -185,6 +185,27 @@
return id;
}
+static void print_printer_details(const char *name, const char *bdaddr, const char *id)
+{
+ char *uri, *escaped;
+
+ escaped = g_strdelimit(g_strdup(name), "\"", '\'');
+ uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
+ bdaddr[0], bdaddr[1],
+ bdaddr[3], bdaddr[4],
+ bdaddr[6], bdaddr[7],
+ bdaddr[9], bdaddr[10],
+ bdaddr[12], bdaddr[13],
+ bdaddr[15], bdaddr[16]);
+ printf("direct %s \"%s\" \"%s (Bluetooth)\"", uri, escaped, escaped);
+ if (id != NULL)
+ printf(" \"%s\"\n", id);
+ else
+ printf("\n");
+ g_free(escaped);
+ g_free(uri);
+}
+
static void add_device_to_list(const char *name, const char *bdaddr, const char *id)
{
struct cups_device *device;
@@ -212,27 +233,7 @@
device->id = g_strdup(id);
device_list = g_slist_prepend(device_list, device);
-}
-
-static void print_printer_details(const char *name, const char *bdaddr, const char *id)
-{
- char *uri, *escaped;
-
- escaped = g_strdelimit(g_strdup(name), "\"", '\'');
- uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
- bdaddr[0], bdaddr[1],
- bdaddr[3], bdaddr[4],
- bdaddr[6], bdaddr[7],
- bdaddr[9], bdaddr[10],
- bdaddr[12], bdaddr[13],
- bdaddr[15], bdaddr[16]);
- printf("network %s \"Unknown\" \"%s (Bluetooth)\"", uri, escaped);
- if (id != NULL)
- printf(" \"%s\"\n", id);
- else
- printf("\n");
- g_free(escaped);
- g_free(uri);
+ print_printer_details(device->name, device->bdaddr, device->id);
}
static gboolean parse_device_properties(DBusMessageIter *reply_iter, char **name, char **bdaddr)
@@ -371,9 +372,10 @@
if (!reply)
return;
- } else {
- if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID) == FALSE)
- return;
+ }
+ if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ return;
}
id = device_get_ieee1284_id(adapter, object_path);
@@ -383,23 +385,6 @@
static void discovery_completed(void)
{
- GSList *l;
-
- for (l = device_list; l != NULL; l = l->next) {
- struct cups_device *device = (struct cups_device *) l->data;
-
- if (device->name == NULL)
- device->name = g_strdelimit(g_strdup(device->bdaddr), ":", '-');
- /* Give another try to getting an ID for the device */
- if (device->id == NULL)
- remote_device_found(NULL, device->bdaddr, device->name);
- print_printer_details(device->name, device->bdaddr, device->id);
- g_free(device->name);
- g_free(device->bdaddr);
- g_free(device->id);
- g_free(device);
- }
-
g_slist_free(device_list);
device_list = NULL;
@@ -441,7 +426,7 @@
dbus_message_unref(message);
- if (&error != NULL && dbus_error_is_set(&error))
+ if (dbus_error_is_set(&error))
return FALSE;
dbus_message_iter_init(reply, &reply_iter);
@@ -506,6 +491,8 @@
dbus_message_iter_init(message, &iter);
dbus_message_iter_get_basic(&iter, &name);
+ if (name == NULL || strcmp(name, "Discovering") != 0)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_next(&iter);
dbus_message_iter_recurse(&iter, &value_iter);
dbus_message_iter_get_basic(&value_iter, &discovering);
@@ -540,7 +527,7 @@
dbus_error_init(&error);
hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
- if (&error != NULL && dbus_error_is_set(&error))
+ if (dbus_error_is_set(&error))
return TRUE;
if (!hcid_exists)
@@ -560,7 +547,7 @@
dbus_message_unref(message);
- if (&error != NULL && dbus_error_is_set(&error)) {
+ if (dbus_error_is_set(&error)) {
dbus_connection_unref(conn);
/* No adapter */
return TRUE;
@@ -612,6 +599,7 @@
loop = g_main_loop_new(NULL, TRUE);
g_main_loop_run(loop);
+ g_free(adapter);
dbus_connection_unref(conn);
return TRUE;
@@ -635,6 +623,9 @@
/* Make sure status messages are not buffered */
setbuf(stderr, NULL);
+ /* Make sure output is not buffered */
+ setbuf(stdout, NULL);
+
/* Ignore SIGPIPE signals */
#ifdef HAVE_SIGSET
sigset(SIGPIPE, SIG_IGN);
diff --git a/cups/sdp.c b/cups/sdp.c
index 8bf6d32..c7f17a4 100644
--- a/cups/sdp.c
+++ b/cups/sdp.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/cups/spp.c b/cups/spp.c
index 3370218..d906ed2 100644
--- a/cups/spp.c
+++ b/cups/spp.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/doc/Makefile.am b/doc/Makefile.am
deleted file mode 100644
index 6277dcc..0000000
--- a/doc/Makefile.am
+++ /dev/null
@@ -1,31 +0,0 @@
-
-DOC_MODULE = bluez
-
-DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml
-
-DOC_SOURCE_DIR = ../src
-
-SCAN_OPTIONS = --rebuild-sections
-
-MKDB_OPTIONS = --sgml-mode --output-format=xml --tmpl-dir=. \
- --source-suffixes=c,h
-
-MKTMPL_OPTIONS = --output-dir=.
-
-HFILE_GLOB = $(top_srcdir)/src/*.h
-CFILE_GLOB = $(top_srcdir)/src/*.c
-
-IGNORE_HFILES =
-
-MAINTAINERCLEANFILES = Makefile.in \
- $(DOC_MODULE).types $(DOC_MODULE)-*.txt *.sgml
-
-if ENABLE_GTK_DOC
-include $(top_srcdir)/doc/gtk-doc.make
-else
-EXTRA_DIST = $(DOC_MAIN_SGML_FILE) $(content_files)
-endif
-
-EXTRA_DIST += manager-api.txt adapter-api.txt device-api.txt \
- service-api.txt agent-api.txt serial-api.txt \
- network-api.txt input-api.txt audio-api.txt control-api.txt
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 1e03b4e..6098c76 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Adapter API description
***********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+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>
@@ -80,9 +80,11 @@
Possible Errors: org.bluez.Error.DoesNotExist
org.bluez.Error.InvalidArguments
- array{object} ListDevices()
+ 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
@@ -268,3 +270,8 @@
array{object} Devices [readonly]
List of device object paths.
+
+ array{string} UUIDs [readonly]
+
+ List of 128-bit UUIDs that represents the available
+ local services.
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index dbfc08a..c927a55 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Agent API description
**********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
Copyright (C) 2005-2006 Johan Hedberg <johan.hedberg@nokia.com>
diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
new file mode 100644
index 0000000..ee91f93
--- /dev/null
+++ b/doc/attribute-api.txt
@@ -0,0 +1,97 @@
+BlueZ D-Bus Attribute API description
+*************************************
+
+Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+
+
+Attribute hierarchy
+===================
+
+Service org.bluez
+Interface org.bluez.Service
+ org.bluez.Characteristic
+Object path [prefix]/{hci0}/{service0}
+ [prefix]/{hci0}/{device0}/{service0}/{characteristic0,...}
+ [prefix]/{hci0}/{device0}/{service1}/{characteristic0,...}
+
+Service details
+---------------
+
+One service object path for every remote SDP record or service in the
+attribute database. One service object path for every local SDP record
+or service from attribute database.
+
+Local services are children of the adapter object path. Remote services
+are children of the remote device object path. This doesn't solve the
+problem where local atttributes can have different instances based on
+the remote device.
+
+In general the idea is to also represent SDP records as services so that
+new style application can just use the service interfaces to retrieve the
+needed information. That way the usage of SDP and GATT would be mostly
+fully transparent and a differentiation becomes unimportant in the future.
+
+A service consists of some generic service information and a set of
+characteristics. All characteristic are presented as object path as well.
+
+Properties
+----------
+ string Name (mandatory)
+
+ General name of service
+
+ string Description (optional)
+
+ Description of service
+
+ string UUID (mandatory)
+
+ UUID of service. Service class value for SDP and GATT UUID
+ for attribute based services.
+
+ array{object} Characteristics
+
+ This list contains the characteristics owned by this specific
+ service and other characteristics from service includes. That
+ way no complicated service includes array is needed.
+
+ string UUID
+ string Name
+ string Description
+ struct Format (type, name, exponet etc.)
+
+ array{byte} Value
+ string Representation (of the binary Value)
+
+ object Service (the original service in case of includes)
+
+ At this point only GetProperties() method call should be
+ supported for simplicity. Changing characteristics is up
+ to future support.
+
+ The object path of the characteristics might be split
+ over multiple service objects, because of includes.
+
+ array[(object, dict)] GetCharacteristics()
+
+ Array of tuples with object path as identifier. An alternativ
+ is doing dict of dict since the object path is unique and the
+ order of characteristics is irrelevant. However it might be
+ good to actually present an order here.
+
+ See Characteristics properties for dictionary details.
+
+ RegisterCharacteristicsWatcher(object path)
+
+ Register a watcher for changes in specific characteristics
+ to monitor changes.
+
+ A watcher will be registered for this service and will
+ notifier about any changed characteristics in the service.
+ This also notifies about any included characteristics.
+
+ Method for the watch objects still need to be defined.
+
+ UnregisterCharacteristicsWatcher(object path)
+
+ Unregister a watcher.
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index 1f09cd5..e7991f3 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Audio API description
*********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+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>
diff --git a/doc/control-api.txt b/doc/control-api.txt
index ffc0fc0..1a42846 100644
--- a/doc/control-api.txt
+++ b/doc/control-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Control API description
***********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
Copyright (C) 2007-2008 David Stockwell <dstockwell@frequency-one.com>
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 698f9ce..b818299 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Device API description
**********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+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>
@@ -154,6 +154,13 @@
Indicates if the remote is seen as trusted. This
setting can be changed by the application.
+ boolean Blocked [readwrite]
+
+ If set to true any incoming connections from the
+ device will be immediately rejected. Any device
+ drivers will also be removed and no new ones will
+ be probed as long as the device is blocked.
+
string Alias [readwrite]
The name alias for the remote device. The alias can
diff --git a/doc/health-api.txt b/doc/health-api.txt
new file mode 100644
index 0000000..f469df3
--- /dev/null
+++ b/doc/health-api.txt
@@ -0,0 +1,168 @@
+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
+===============================
+
+Service org.bluez
+Interface org.bluez.HealthManager
+Object path /org/bluez/
+
+Methods:
+
+ object CreateApplication(dict config, object agent)
+
+ Returns the path of the new registered application. The agent
+ parameter is the path of the object with the callbacks to
+ notify events (see org.bluez.HealthAgent at the end
+ of this document).
+
+ Dict is defined as bellow:
+ {
+ "DataType": uint16, (mandatory)
+ "Role" : ("Source" or "Sink"), (mandatory)
+ "Description" : string, (optional)
+ "ChannelType" : ("Reliable" or "Streaming")
+ (just for Sources, optional)
+ }
+
+ Application will be closed by the call or implicitly when the
+ programs leaves the bus.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ void DestroyApplication(object application)
+
+ Closes the HDP application identified by the object path. Also
+ application will be closed if the process that started it leaves
+ the bus.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthApplication
+Object path [variable prefix]/health_app_ZZZZ
+
+Methods:
+
+ void Echo(object service)
+
+ 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 and the associated MCL is closed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.OutOfRange
+
+ object CreateChannel(object service, string type)
+
+ Creates a new data channel with the indicated config to the
+ remote Service.
+ The configuration should indicate the channel quality of
+ service using one of this values "Reliable", "Streaming", "Any".
+
+ Returns the object path that identifies the data channel that
+ is already connected.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.HealthError
+
+ void DestroyChannel(object channel)
+
+ Destroys the data channel object.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ orb.bluez.Error.NotFound
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthService
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/hdp_YYYY
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthChannel
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
+ hdp_YYYY/channel_ZZ
+
+Methods:
+
+ dict GetProperties()
+
+ Returns all properties for the interface. See the properties
+ section for available properties.
+
+ fd Acquire()
+
+ Returns the file descriptor for this data channel. If the data
+ channel is not connected it will also reconnect.
+
+ Possible errors: org.bluez.Error.NotConnected
+
+ void Release()
+
+ Releases the fd. Application should also need to close() it.
+
+Properties:
+
+ string Type (read only)
+
+ The quality of service of the data channel. ("Reliable" or
+ "Streaming")
+
+ object Service (read only)
+
+ Identifies the Remote Service that is connected with. Maps with
+ a HealthService object.
+
+HealthAgent hierarchy
+=====================
+
+(this object is implemented by the HDP user in order to receive notifications)
+
+Service unique name
+Interface org.bluez.HealthAgent
+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.
+
+ void ServiceDiscovered(object service)
+
+ This method is called when a device containing an HDP
+ application is paired or when the method Update of the
+ HealthManager is called and new HealthServices are discovered.
+ The method will be called once for each HealthService.
+
+ void ServiceRemoved(object service)
+
+ This is called if during an Update some HealthServices
+ have disappeared. The method is called once for each removed
+ HealthService.
+
+ void ChannelConnected(object channel)
+
+ This method is called when a new data channel is created or when
+ a known data channel is reconnected.
+
+ void ChannelDeleted(object channel)
+
+ This method is called when a data channel is deleted.
+
+ After this call the data channel path will not be valid and can
+ be reused for future creation of data channels.
diff --git a/doc/hfp-api.txt b/doc/hfp-api.txt
new file mode 100644
index 0000000..93251e8
--- /dev/null
+++ b/doc/hfp-api.txt
@@ -0,0 +1,86 @@
+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)
+
+ This method gets called whenever a new handsfree
+ connection has been established. The objectpath
+ contains the object path of the remote device. This
+ method assumes that DBus daemon with file descriptor
+ passing capability is being used.
+
+ 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
index 38310ce..7c3a4b2 100644
--- a/doc/input-api.txt
+++ b/doc/input-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Input API description
*********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
Input hierarchy
diff --git a/doc/manager-api.txt b/doc/manager-api.txt
index e045cad..d2c1caf 100644
--- a/doc/manager-api.txt
+++ b/doc/manager-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Manager API description
***********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+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>
@@ -37,9 +37,11 @@
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.NoSuchAdapter
- array{object} ListAdapters()
+ array{object} ListAdapters() {deprecated}
- Returns list of adapter object paths under /org/bluez
+ 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
diff --git a/doc/network-api.txt b/doc/network-api.txt
index 7271193..4dd3e58 100644
--- a/doc/network-api.txt
+++ b/doc/network-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Network API description
***********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
Network hierarchy
@@ -14,8 +14,16 @@
Methods string Connect(string uuid)
Connect to the network device and return the network
- device name. Examples of the device name are bnep0,
- bnep1 etc.
+ interface name. Examples of the interface name are
+ bnep0, bnep1 etc.
+
+ uuid can be either one of "gn", "panu" or "nap" (case
+ insensitive) or a traditional string representation of
+ UUID or a hexadecimal number.
+
+ The connection will be closed and network device
+ released either upon calling Disconnect() or when
+ the client disappears from the message bus.
Possible errors: org.bluez.Error.AlreadyConnected
org.bluez.Error.ConnectionAttemptFailed
@@ -43,7 +51,7 @@
Indicates if the device is connected.
- string Device [readonly]
+ string Interface [readonly]
Indicates the network interface name when available.
@@ -52,35 +60,29 @@
Indicates the connection role when available.
-Network Hub/Peer/Router hierarchy
-=================
+Network server hierarchy
+========================
Service org.bluez
-Interface org.bluez.network.{Hub, Peer, Router}
+Interface org.bluez.NetworkServer
Object path /org/bluez/{hci0,hci1,...}
-Methods dict GetProperties()
+Methods void Register(string uuid, string bridge)
- Returns all properties for the GN/PANU/NAP server. See the
- properties section for available properties.
+ Register server for the provided UUID. Every new
+ connection to this server will be added the bridge
+ interface.
- void SetProperty(string name, variant value)
+ Valid UUIDs are "gn", "panu" or "nap".
- Changes the value of the specified property. Only
- properties that are listed a read-write are changeable.
- On success this will emit a PropertyChanged signal.
+ Initially no network server SDP is provided. Only
+ after this method a SDP record will be available
+ and the BNEP server will be ready for incoming
+ connections.
- Possible Errors: org.bluez.Error.DoesNotExist
- org.bluez.Error.InvalidArguments
+ void Unregister(string uuid)
-Properties string Name[readwrite]
+ Unregister the server for provided UUID.
- The Bluetooth network server name.
-
- boolean Enable[readwrite]
-
- Indicates if the server is Enabled/Disabled.
-
- string Uuid[readonly]
-
- The Bluetooth network server UUID 128 identification.
+ All servers will be automatically unregistered when
+ the calling application terminates.
diff --git a/doc/node-api.txt b/doc/node-api.txt
index 7a33dab..3ae4dee 100644
--- a/doc/node-api.txt
+++ b/doc/node-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Node API description
********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
Node hierarchy
diff --git a/doc/serial-api.txt b/doc/serial-api.txt
index b4c806a..5f9bd5f 100644
--- a/doc/serial-api.txt
+++ b/doc/serial-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Serial API description
**********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
Serial hierarchy
diff --git a/doc/service-api.txt b/doc/service-api.txt
index c9489fb..5c8c7f3 100644
--- a/doc/service-api.txt
+++ b/doc/service-api.txt
@@ -1,7 +1,7 @@
BlueZ D-Bus Adapter API description
***********************************
-Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+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>
diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am
deleted file mode 100644
index 9447555..0000000
--- a/gdbus/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-
-noinst_LTLIBRARIES = libgdbus.la
-
-libgdbus_la_SOURCES = gdbus.h mainloop.c object.c watch.c
-
-AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index fa618a5..47e18cf 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -2,7 +2,7 @@
*
* D-Bus helper library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -40,10 +40,11 @@
DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
DBusError *error);
-gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
DBusError *error);
-gboolean g_dbus_check_service(DBusConnection *connection, const char *name);
+gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+ DBusError *error);
gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
GDBusWatchFunction function,
@@ -90,9 +91,9 @@
gboolean g_dbus_register_interface(DBusConnection *connection,
const char *path, const char *name,
- GDBusMethodTable *methods,
- GDBusSignalTable *signals,
- GDBusPropertyTable *properties,
+ const GDBusMethodTable *methods,
+ const GDBusSignalTable *signals,
+ const GDBusPropertyTable *properties,
void *user_data,
GDBusDestroyFunction destroy);
gboolean g_dbus_unregister_interface(DBusConnection *connection,
@@ -127,8 +128,10 @@
GDBusWatchFunction function,
void *user_data, GDBusDestroyFunction destroy);
guint g_dbus_add_signal_watch(DBusConnection *connection,
- const char *rule, GDBusSignalFunction function,
- void *user_data, GDBusDestroyFunction destroy);
+ const char *sender, const char *path,
+ const char *interface, const char *member,
+ GDBusSignalFunction function, void *user_data,
+ GDBusDestroyFunction destroy);
gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag);
void g_dbus_remove_all_watches(DBusConnection *connection);
diff --git a/gdbus/mainloop.c b/gdbus/mainloop.c
index eaba42e..ec10ab0 100644
--- a/gdbus/mainloop.c
+++ b/gdbus/mainloop.c
@@ -2,7 +2,7 @@
*
* D-Bus helper library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -25,8 +25,6 @@
#include <config.h>
#endif
-#include <stdint.h>
-
#include <glib.h>
#include <dbus/dbus.h>
@@ -42,116 +40,131 @@
#define error(fmt...)
#define debug(fmt...)
-typedef struct {
- uint32_t id;
+struct timeout_handler {
+ guint id;
DBusTimeout *timeout;
-} timeout_handler_t;
+};
struct watch_info {
- guint watch_id;
- GIOChannel *io;
+ guint id;
+ DBusWatch *watch;
DBusConnection *conn;
};
-struct server_info {
- guint watch_id;
- GIOChannel *io;
- DBusServer *server;
-};
-
struct disconnect_data {
- GDBusWatchFunction disconnect_cb;
+ GDBusWatchFunction function;
void *user_data;
};
-static DBusHandlerResult disconnect_filter(DBusConnection *conn,
+static gboolean disconnected_signal(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct disconnect_data *dc_data = data;
- if (dbus_message_is_signal(msg,
- DBUS_INTERFACE_LOCAL, "Disconnected") == TRUE) {
- error("Got disconnected from the system message bus");
- dc_data->disconnect_cb(conn, dc_data->user_data);
- dbus_connection_unref(conn);
- }
+ error("Got disconnected from the system message bus");
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ dc_data->function(conn, dc_data->user_data);
+
+ dbus_connection_unref(conn);
+
+ return TRUE;
}
-static gboolean message_dispatch_cb(void *data)
+static gboolean message_dispatch(void *data)
{
- DBusConnection *connection = data;
+ DBusConnection *conn = data;
- dbus_connection_ref(connection);
+ dbus_connection_ref(conn);
/* Dispatch messages */
- while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+ while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS);
- dbus_connection_unref(connection);
+ dbus_connection_unref(conn);
return FALSE;
}
+static inline void queue_dispatch(DBusConnection *conn,
+ DBusDispatchStatus status)
+{
+ if (status == DBUS_DISPATCH_DATA_REMAINS)
+ g_timeout_add(DISPATCH_TIMEOUT, message_dispatch, conn);
+}
+
static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
{
- DBusWatch *watch = data;
- struct watch_info *info = dbus_watch_get_data(watch);
- int flags = 0;
+ struct watch_info *info = data;
+ unsigned int flags = 0;
+
+ dbus_connection_ref(info->conn);
if (cond & G_IO_IN) flags |= DBUS_WATCH_READABLE;
if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
- dbus_watch_handle(watch, flags);
+ dbus_watch_handle(info->watch, flags);
- if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS)
- g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn);
+ dbus_connection_unref(info->conn);
return TRUE;
}
+static void watch_info_free(void *data)
+{
+ struct watch_info *info = data;
+
+ if (info->id > 0) {
+ g_source_remove(info->id);
+ info->id = 0;
+ }
+
+ dbus_connection_unref(info->conn);
+
+ g_free(info);
+}
+
static dbus_bool_t add_watch(DBusWatch *watch, void *data)
{
- GIOCondition cond = G_IO_HUP | G_IO_ERR;
DBusConnection *conn = data;
+ GIOCondition cond = G_IO_HUP | G_IO_ERR;
+ GIOChannel *chan;
struct watch_info *info;
- int fd, flags;
+ unsigned int flags;
+ int fd;
if (!dbus_watch_get_enabled(watch))
return TRUE;
- info = g_new(struct watch_info, 1);
+ info = g_new0(struct watch_info, 1);
fd = dbus_watch_get_unix_fd(watch);
- info->io = g_io_channel_unix_new(fd);
+ chan = g_io_channel_unix_new(fd);
+
+ info->watch = watch;
info->conn = dbus_connection_ref(conn);
- dbus_watch_set_data(watch, info, NULL);
+ dbus_watch_set_data(watch, info, watch_info_free);
flags = dbus_watch_get_flags(watch);
if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
- info->watch_id = g_io_add_watch(info->io, cond, watch_func, watch);
+ info->id = g_io_add_watch(chan, cond, watch_func, info);
+
+ g_io_channel_unref(chan);
return TRUE;
}
static void remove_watch(DBusWatch *watch, void *data)
{
- struct watch_info *info = dbus_watch_get_data(watch);
+ if (dbus_watch_get_enabled(watch))
+ return;
+ /* will trigger watch_info_free() */
dbus_watch_set_data(watch, NULL, NULL);
-
- if (info) {
- g_source_remove(info->watch_id);
- g_io_channel_unref(info->io);
- dbus_connection_unref(info->conn);
- g_free(info);
- }
}
static void watch_toggled(DBusWatch *watch, void *data)
@@ -166,10 +179,12 @@
static gboolean timeout_handler_dispatch(gpointer data)
{
- timeout_handler_t *handler = data;
+ struct timeout_handler *handler = data;
+
+ handler->id = 0;
/* if not enabled should not be polled by the main loop */
- if (dbus_timeout_get_enabled(handler->timeout) != TRUE)
+ if (!dbus_timeout_get_enabled(handler->timeout))
return FALSE;
dbus_timeout_handle(handler->timeout);
@@ -179,34 +194,43 @@
static void timeout_handler_free(void *data)
{
- timeout_handler_t *handler = data;
- if (!handler)
- return;
+ struct timeout_handler *handler = data;
- g_source_remove(handler->id);
+ if (handler->id > 0) {
+ g_source_remove(handler->id);
+ handler->id = 0;
+ }
+
g_free(handler);
}
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
{
- timeout_handler_t *handler;
+ int interval = dbus_timeout_get_interval(timeout);
+ struct timeout_handler *handler;
if (!dbus_timeout_get_enabled(timeout))
return TRUE;
- handler = g_new0(timeout_handler_t, 1);
+ handler = g_new0(struct timeout_handler, 1);
handler->timeout = timeout;
- handler->id = g_timeout_add(dbus_timeout_get_interval(timeout),
- timeout_handler_dispatch, handler);
dbus_timeout_set_data(timeout, handler, timeout_handler_free);
+ handler->id = g_timeout_add(interval, timeout_handler_dispatch,
+ handler);
+
return TRUE;
}
static void remove_timeout(DBusTimeout *timeout, void *data)
{
+ if (dbus_timeout_get_enabled(timeout))
+ return;
+
+ /* will trigger timeout_handler_free() */
+ dbus_timeout_set_data(timeout, NULL, NULL);
}
static void timeout_toggled(DBusTimeout *timeout, void *data)
@@ -217,26 +241,51 @@
remove_timeout(timeout, data);
}
-static void dispatch_status_cb(DBusConnection *conn,
- DBusDispatchStatus new_status, void *data)
+static void dispatch_status(DBusConnection *conn,
+ DBusDispatchStatus status, void *data)
{
if (!dbus_connection_get_is_connected(conn))
return;
- if (new_status == DBUS_DISPATCH_DATA_REMAINS)
- g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, data);
+ queue_dispatch(conn, status);
}
-static void setup_dbus_with_main_loop(DBusConnection *conn)
+static inline void setup_dbus_with_main_loop(DBusConnection *conn)
{
dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
watch_toggled, conn, NULL);
dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
- timeout_toggled, conn, NULL);
+ timeout_toggled, NULL, NULL);
- dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
- conn, NULL);
+ dbus_connection_set_dispatch_status_function(conn, dispatch_status,
+ NULL, NULL);
+}
+
+static gboolean setup_bus(DBusConnection *conn, const char *name,
+ DBusError *error)
+{
+ gboolean result;
+ DBusDispatchStatus status;
+
+ if (name != NULL) {
+ result = g_dbus_request_name(conn, name, error);
+
+ if (error != NULL) {
+ if (dbus_error_is_set(error) == TRUE)
+ return FALSE;
+ }
+
+ if (result == FALSE)
+ return FALSE;
+ }
+
+ setup_dbus_with_main_loop(conn);
+
+ status = dbus_connection_get_dispatch_status(conn);
+ queue_dispatch(conn, status);
+
+ return TRUE;
}
DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
@@ -254,23 +303,33 @@
if (conn == NULL)
return NULL;
- if (name != NULL) {
- if (dbus_bus_request_name(conn, name,
- DBUS_NAME_FLAG_DO_NOT_QUEUE, error) !=
- DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ) {
- dbus_connection_unref(conn);
- return NULL;
- }
-
- if (error != NULL) {
- if (dbus_error_is_set(error) == TRUE) {
- dbus_connection_unref(conn);
- return NULL;
- }
- }
+ if (setup_bus(conn, name, error) == FALSE) {
+ dbus_connection_unref(conn);
+ return NULL;
}
- setup_dbus_with_main_loop(conn);
+ return conn;
+}
+
+DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
+ DBusError *error)
+{
+ DBusConnection *conn;
+
+ conn = dbus_bus_get_private(type, error);
+
+ if (error != NULL) {
+ if (dbus_error_is_set(error) == TRUE)
+ return NULL;
+ }
+
+ if (conn == NULL)
+ return NULL;
+
+ if (setup_bus(conn, name, error) == FALSE) {
+ dbus_connection_unref(conn);
+ return NULL;
+ }
return conn;
}
@@ -278,68 +337,43 @@
gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
DBusError *error)
{
+ int result;
+
+ result = dbus_bus_request_name(connection, name,
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
+
+ if (error != NULL) {
+ if (dbus_error_is_set(error) == TRUE)
+ return FALSE;
+ }
+
+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ if (error != NULL)
+ dbus_set_error(error, name, "Name already in use");
+
+ return FALSE;
+ }
+
return TRUE;
}
-gboolean g_dbus_check_service(DBusConnection *connection, const char *name)
-{
- DBusMessage *message, *reply;
- const char **names;
- int i, count;
- gboolean result = FALSE;
-
- message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ListNames");
- if (message == NULL) {
- error("Can't allocate new message");
- return FALSE;
- }
-
- reply = dbus_connection_send_with_reply_and_block(connection,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (reply == NULL) {
- error("Failed to execute method call");
- return FALSE;
- }
-
- if (dbus_message_get_args(reply, NULL,
- DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
- &names, &count, DBUS_TYPE_INVALID) == FALSE) {
- error("Failed to read name list");
- goto done;
- }
-
- for (i = 0; i < count; i++)
- if (g_str_equal(names[i], name) == TRUE) {
- result = TRUE;
- break;
- }
-
-done:
- dbus_message_unref(reply);
-
- return result;
-}
-
gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
GDBusWatchFunction function,
void *user_data, DBusFreeFunction destroy)
{
struct disconnect_data *dc_data;
- dc_data = g_new(struct disconnect_data, 1);
+ dc_data = g_new0(struct disconnect_data, 1);
- dc_data->disconnect_cb = function;
+ dc_data->function = function;
dc_data->user_data = user_data;
dbus_connection_set_exit_on_disconnect(connection, FALSE);
- if (dbus_connection_add_filter(connection, disconnect_filter,
- dc_data, g_free) == FALSE) {
- error("Can't add D-Bus disconnect filter");
+ if (g_dbus_add_signal_watch(connection, NULL, NULL,
+ DBUS_INTERFACE_LOCAL, "Disconnected",
+ disconnected_signal, dc_data, g_free) == 0) {
+ error("Failed to add watch for D-Bus Disconnected signal");
g_free(dc_data);
return FALSE;
}
diff --git a/gdbus/object.c b/gdbus/object.c
index 3186921..ff69641 100644
--- a/gdbus/object.c
+++ b/gdbus/object.c
@@ -2,7 +2,7 @@
*
* D-Bus helper library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -45,9 +45,9 @@
struct interface_data {
char *name;
- GDBusMethodTable *methods;
- GDBusSignalTable *signals;
- GDBusPropertyTable *properties;
+ const GDBusMethodTable *methods;
+ const GDBusSignalTable *signals;
+ const GDBusPropertyTable *properties;
void *user_data;
GDBusDestroyFunction destroy;
};
@@ -114,8 +114,8 @@
static void generate_interface_xml(GString *gstr, struct interface_data *iface)
{
- GDBusMethodTable *method;
- GDBusSignalTable *signal;
+ const GDBusMethodTable *method;
+ const GDBusSignalTable *signal;
for (method = iface->methods; method && method->name; method++) {
if (!strlen(method->signature) && !strlen(method->reply))
@@ -183,14 +183,15 @@
data->introspect = g_string_free(gstr, FALSE);
}
-static DBusHandlerResult introspect(DBusConnection *connection,
- DBusMessage *message, struct generic_data *data)
+static DBusMessage *introspect(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
{
+ struct generic_data *data = user_data;
DBusMessage *reply;
if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) {
error("Unexpected signature to introspect call");
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return NULL;
}
if (!data->introspect)
@@ -199,16 +200,12 @@
reply = dbus_message_new_method_return(message);
if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ return NULL;
dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
DBUS_TYPE_INVALID);
- dbus_connection_send(connection, reply, NULL);
-
- dbus_message_unref(reply);
-
- return DBUS_HANDLER_RESULT_HANDLED;
+ return reply;
}
static void generic_unregister(DBusConnection *connection, void *user_data)
@@ -241,14 +238,9 @@
{
struct generic_data *data = user_data;
struct interface_data *iface;
- GDBusMethodTable *method;
+ const GDBusMethodTable *method;
const char *interface;
- if (dbus_message_is_method_call(message,
- DBUS_INTERFACE_INTROSPECTABLE,
- "Introspect"))
- return introspect(connection, message, data);
-
interface = dbus_message_get_interface(message);
iface = find_interface(data->interfaces, interface);
@@ -316,8 +308,10 @@
goto done;
if (!dbus_connection_get_object_path_data(conn, parent_path,
- (void *) &data))
+ (void *) &data)) {
+ invalidate_parent_data(conn, parent_path);
goto done;
+ }
if (!data)
goto done;
@@ -329,6 +323,31 @@
g_free(parent_path);
}
+static GDBusMethodTable introspect_methods[] = {
+ { "Introspect", "", "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)
+{
+ struct interface_data *iface;
+
+ 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);
+}
+
static struct generic_data *object_path_ref(DBusConnection *connection,
const char *path)
{
@@ -357,9 +376,31 @@
invalidate_parent_data(connection, path);
+ add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
+ introspect_methods, NULL, NULL, data, NULL);
+
return data;
}
+static gboolean remove_interface(struct generic_data *data, const char *name)
+{
+ struct interface_data *iface;
+
+ iface = find_interface(data->interfaces, name);
+ if (!iface)
+ return FALSE;
+
+ data->interfaces = g_slist_remove(data->interfaces, iface);
+
+ if (iface->destroy)
+ iface->destroy(iface->user_data);
+
+ g_free(iface->name);
+ g_free(iface);
+
+ return TRUE;
+}
+
static void object_path_unref(DBusConnection *connection, const char *path)
{
struct generic_data *data = NULL;
@@ -376,6 +417,8 @@
if (data->refcount > 0)
return;
+ remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
+
invalidate_parent_data(connection, path);
dbus_connection_unregister_object_path(connection, path);
@@ -387,7 +430,7 @@
{
struct generic_data *data = NULL;
struct interface_data *iface;
- GDBusSignalTable *signal;
+ const GDBusSignalTable *signal;
*args = NULL;
if (!dbus_connection_get_object_path_data(conn, path,
@@ -461,32 +504,25 @@
gboolean g_dbus_register_interface(DBusConnection *connection,
const char *path, const char *name,
- GDBusMethodTable *methods,
- GDBusSignalTable *signals,
- GDBusPropertyTable *properties,
+ const GDBusMethodTable *methods,
+ const GDBusSignalTable *signals,
+ const GDBusPropertyTable *properties,
void *user_data,
GDBusDestroyFunction destroy)
{
struct generic_data *data;
- struct interface_data *iface;
data = object_path_ref(connection, path);
if (data == NULL)
return FALSE;
- if (find_interface(data->interfaces, name))
+ if (find_interface(data->interfaces, name)) {
+ object_path_unref(connection, path);
return FALSE;
+ }
- 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);
+ add_interface(data, name, methods, signals,
+ properties, user_data, destroy);
g_free(data->introspect);
data->introspect = NULL;
@@ -498,7 +534,6 @@
const char *path, const char *name)
{
struct generic_data *data = NULL;
- struct interface_data *iface;
if (!path)
return FALSE;
@@ -510,18 +545,9 @@
if (data == NULL)
return FALSE;
- iface = find_interface(data->interfaces, name);
- if (!iface)
+ if (remove_interface(data, name) == FALSE)
return FALSE;
- data->interfaces = g_slist_remove(data->interfaces, iface);
-
- if (iface->destroy)
- iface->destroy(iface->user_data);
-
- g_free(iface->name);
- g_free(iface);
-
g_free(data->introspect);
data->introspect = NULL;
diff --git a/gdbus/watch.c b/gdbus/watch.c
index c7a4e69..1d479fa 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -2,7 +2,7 @@
*
* D-Bus helper library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -37,52 +37,198 @@
#define error(fmt...)
#define debug(fmt...)
-static DBusHandlerResult name_exit_filter(DBusConnection *connection,
+static DBusHandlerResult message_filter(DBusConnection *connection,
DBusMessage *message, void *user_data);
static guint listener_id = 0;
-static GSList *name_listeners = NULL;
+static GSList *listeners = NULL;
-struct name_callback {
+struct filter_callback {
GDBusWatchFunction conn_func;
GDBusWatchFunction disc_func;
+ GDBusSignalFunction signal_func;
+ GDBusDestroyFunction destroy_func;
void *user_data;
guint id;
};
-struct name_data {
+struct filter_data {
DBusConnection *connection;
- char *name;
+ DBusHandleMessageFunction handle_func;
+ char *sender;
+ char *path;
+ char *interface;
+ char *member;
+ char *argument;
GSList *callbacks;
GSList *processed;
gboolean lock;
+ gboolean registered;
};
-static struct name_data *name_data_find(DBusConnection *connection,
- const char *name)
+static struct filter_data *filter_data_find(DBusConnection *connection,
+ const char *sender,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *argument)
{
GSList *current;
- for (current = name_listeners;
+ for (current = listeners;
current != NULL; current = current->next) {
- struct name_data *data = current->data;
+ struct filter_data *data = current->data;
if (connection != data->connection)
continue;
- if (name == NULL || g_str_equal(name, data->name))
- return data;
+ if (sender && data->sender &&
+ g_str_equal(sender, data->sender) == FALSE)
+ continue;
+
+ if (path && data->path &&
+ g_str_equal(path, data->path) == FALSE)
+ continue;
+
+ if (interface && data->interface &&
+ g_str_equal(interface, data->interface) == FALSE)
+ continue;
+
+ if (member && data->member &&
+ g_str_equal(member, data->member) == FALSE)
+ continue;
+
+ if (argument && data->argument &&
+ g_str_equal(argument, data->argument) == FALSE)
+ continue;
+
+ return data;
}
return NULL;
}
-static struct name_callback *name_callback_find(GSList *callbacks, guint id)
+static void format_rule(struct filter_data *data, char *rule, size_t size)
{
- GSList *current;
+ int offset;
- for (current = callbacks; current != NULL; current = current->next) {
- struct name_callback *cb = current->data;
+ offset = snprintf(rule, size, "type='signal'");
+
+ if (data->sender)
+ offset += snprintf(rule + offset, size - offset,
+ ",sender='%s'", data->sender);
+ if (data->path)
+ offset += snprintf(rule + offset, size - offset,
+ ",path='%s'", data->path);
+ if (data->interface)
+ offset += snprintf(rule + offset, size - offset,
+ ",interface='%s'", data->interface);
+ if (data->member)
+ offset += snprintf(rule + offset, size - offset,
+ ",member='%s'", data->member);
+ if (data->argument)
+ snprintf(rule + offset, size - offset,
+ ",arg0='%s'", data->argument);
+}
+
+static gboolean add_match(struct filter_data *data,
+ DBusHandleMessageFunction filter)
+{
+ DBusError err;
+ char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+
+ format_rule(data, rule, sizeof(rule));
+ dbus_error_init(&err);
+
+ dbus_bus_add_match(data->connection, rule, &err);
+ if (dbus_error_is_set(&err)) {
+ error("Adding match rule \"%s\" failed: %s", rule,
+ err.message);
+ dbus_error_free(&err);
+ return FALSE;
+ }
+
+ data->handle_func = filter;
+ data->registered = TRUE;
+
+ return TRUE;
+}
+
+static gboolean remove_match(struct filter_data *data)
+{
+ DBusError err;
+ char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+
+ format_rule(data, rule, sizeof(rule));
+
+ dbus_error_init(&err);
+
+ dbus_bus_remove_match(data->connection, rule, &err);
+ if (dbus_error_is_set(&err)) {
+ error("Removing owner match rule for %s failed: %s",
+ rule, err.message);
+ dbus_error_free(&err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static struct filter_data *filter_data_get(DBusConnection *connection,
+ DBusHandleMessageFunction filter,
+ const char *sender,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *argument)
+{
+ struct filter_data *data;
+
+ if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL)) {
+ if (!dbus_connection_add_filter(connection,
+ message_filter, NULL, NULL)) {
+ error("dbus_connection_add_filter() failed");
+ return NULL;
+ }
+ }
+
+ data = filter_data_find(connection, sender, path, interface, member,
+ argument);
+ if (data)
+ return data;
+
+ data = g_new0(struct filter_data, 1);
+
+ data->connection = dbus_connection_ref(connection);
+ data->sender = g_strdup(sender);
+ data->path = g_strdup(path);
+ data->interface = g_strdup(interface);
+ data->member = g_strdup(member);
+ data->argument = g_strdup(argument);
+
+ if (!add_match(data, filter)) {
+ g_free(data);
+ return NULL;
+ }
+
+ listeners = g_slist_append(listeners, data);
+
+ return data;
+}
+
+static struct filter_callback *filter_data_find_callback(
+ struct filter_data *data,
+ guint id)
+{
+ GSList *l;
+
+ for (l = data->callbacks; l; l = l->next) {
+ struct filter_callback *cb = l->data;
+ if (cb->id == id)
+ return cb;
+ }
+ for (l = data->processed; l; l = l->next) {
+ struct filter_callback *cb = l->data;
if (cb->id == id)
return cb;
}
@@ -90,23 +236,7 @@
return NULL;
}
-static void name_data_call_and_free(struct name_data *data)
-{
- GSList *l;
-
- for (l = data->callbacks; l != NULL; l = l->next) {
- struct name_callback *cb = l->data;
- if (cb->disc_func)
- cb->disc_func(data->connection, cb->user_data);
- g_free(cb);
- }
-
- g_slist_free(data->callbacks);
- g_free(data->name);
- g_free(data);
-}
-
-static void name_data_free(struct name_data *data)
+static void filter_data_free(struct filter_data *data)
{
GSList *l;
@@ -114,134 +244,127 @@
g_free(l->data);
g_slist_free(data->callbacks);
- g_free(data->name);
+ g_free(data->sender);
+ g_free(data->path);
+ g_free(data->interface);
+ g_free(data->member);
+ g_free(data->argument);
+ dbus_connection_unref(data->connection);
g_free(data);
}
-static int name_data_add(DBusConnection *connection, const char *name,
+static void filter_data_call_and_free(struct filter_data *data)
+{
+ GSList *l;
+
+ for (l = data->callbacks; l != NULL; l = l->next) {
+ struct filter_callback *cb = l->data;
+ if (cb->disc_func)
+ cb->disc_func(data->connection, cb->user_data);
+ if (cb->destroy_func)
+ cb->destroy_func(cb->user_data);
+ g_free(cb);
+ }
+
+ filter_data_free(data);
+}
+
+static struct filter_callback *filter_data_add_callback(
+ struct filter_data *data,
GDBusWatchFunction connect,
GDBusWatchFunction disconnect,
- void *user_data, guint id)
+ GDBusSignalFunction signal,
+ GDBusDestroyFunction destroy,
+ void *user_data)
{
- int first = 1;
- struct name_data *data = NULL;
- struct name_callback *cb = NULL;
+ struct filter_callback *cb = NULL;
- cb = g_new(struct name_callback, 1);
+ cb = g_new(struct filter_callback, 1);
cb->conn_func = connect;
cb->disc_func = disconnect;
+ cb->signal_func = signal;
+ cb->destroy_func = destroy;
cb->user_data = user_data;
- cb->id = id;
+ cb->id = ++listener_id;
- data = name_data_find(connection, name);
- if (data) {
- first = 0;
- goto done;
- }
-
- data = g_new0(struct name_data, 1);
-
- data->connection = connection;
- data->name = g_strdup(name);
-
- name_listeners = g_slist_append(name_listeners, data);
-
-done:
if (data->lock)
data->processed = g_slist_append(data->processed, cb);
else
data->callbacks = g_slist_append(data->callbacks, cb);
- return first;
+ return cb;
}
-static void name_data_remove(DBusConnection *connection,
- const char *name, guint id)
+static gboolean filter_data_remove_callback(struct filter_data *data,
+ struct filter_callback *cb)
{
- struct name_data *data;
- struct name_callback *cb = NULL;
+ DBusConnection *connection;
- data = name_data_find(connection, name);
- if (!data)
- return;
+ data->callbacks = g_slist_remove(data->callbacks, cb);
+ data->processed = g_slist_remove(data->processed, cb);
- cb = name_callback_find(data->callbacks, id);
- if (cb) {
- data->callbacks = g_slist_remove(data->callbacks, cb);
- g_free(cb);
- }
+ if (cb->destroy_func)
+ cb->destroy_func(cb->user_data);
- if (data->callbacks)
- return;
+ g_free(cb);
- name_listeners = g_slist_remove(name_listeners, data);
- name_data_free(data);
+ /* Don't remove the filter if other callbacks exist or data is lock
+ * processing callbacks */
+ if (data->callbacks || data->lock)
+ return TRUE;
+
+ 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 = name_data_find(connection, NULL);
+ data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
if (!data)
- dbus_connection_remove_filter(connection,
- name_exit_filter,
+ dbus_connection_remove_filter(connection, message_filter,
NULL);
-}
-static gboolean add_match(DBusConnection *connection, const char *name)
-{
- DBusError err;
- char match_string[128];
-
- snprintf(match_string, sizeof(match_string),
- "interface=%s,member=NameOwnerChanged,arg0=%s",
- DBUS_INTERFACE_DBUS, name);
-
- dbus_error_init(&err);
-
- dbus_bus_add_match(connection, match_string, &err);
-
- if (dbus_error_is_set(&err)) {
- error("Adding match rule \"%s\" failed: %s", match_string,
- err.message);
- dbus_error_free(&err);
- return FALSE;
- }
+ dbus_connection_unref(connection);
return TRUE;
}
-static gboolean remove_match(DBusConnection *connection, const char *name)
-{
- DBusError err;
- char match_string[128];
-
- snprintf(match_string, sizeof(match_string),
- "interface=%s,member=NameOwnerChanged,arg0=%s",
- DBUS_INTERFACE_DBUS, name);
-
- dbus_error_init(&err);
-
- dbus_bus_remove_match(connection, match_string, &err);
-
- if (dbus_error_is_set(&err)) {
- error("Removing owner match rule for %s failed: %s",
- name, err.message);
- dbus_error_free(&err);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static DBusHandlerResult name_exit_filter(DBusConnection *connection,
+static DBusHandlerResult signal_filter(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
- struct name_data *data;
- struct name_callback *cb;
- char *name, *old, *new;
+ struct filter_data *data = user_data;
+ struct filter_callback *cb;
- if (!dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
- "NameOwnerChanged"))
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ while (data->callbacks) {
+ cb = data->callbacks->data;
+
+ if (cb->signal_func && !cb->signal_func(connection, message,
+ cb->user_data)) {
+ filter_data_remove_callback(data, cb);
+ continue;
+ }
+
+ /* Check if the watch was removed/freed by the callback
+ * function */
+ if (!g_slist_find(data->callbacks, cb))
+ continue;
+
+ data->callbacks = g_slist_remove(data->callbacks, cb);
+ data->processed = g_slist_append(data->processed, cb);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult service_filter(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct filter_data *data = user_data;
+ struct filter_callback *cb;
+ char *name, *old, *new;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
@@ -252,14 +375,6 @@
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- data = name_data_find(connection, name);
- if (!data) {
- error("Got NameOwnerChanged signal for %s which has no listeners", name);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- data->lock = TRUE;
-
while (data->callbacks) {
cb = data->callbacks->data;
@@ -286,60 +401,172 @@
data->processed = g_slist_append(data->processed, cb);
}
- data->callbacks = data->processed;
- data->processed = NULL;
- data->lock = FALSE;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct filter_data *data;
+ const char *sender, *path, *iface, *member, *arg = NULL;
+
+ /* Only filter signals */
+ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ sender = dbus_message_get_sender(message);
+ path = dbus_message_get_path(message);
+ iface = dbus_message_get_interface(message);
+ member = dbus_message_get_member(message);
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
+
+ data = filter_data_find(connection, sender, path, iface, member, arg);
+ if (!data) {
+ error("Got %s.%s signal which has no listeners", iface, member);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (data->handle_func) {
+ data->lock = TRUE;
+
+ data->handle_func(connection, message, data);
+
+ data->callbacks = data->processed;
+ data->processed = NULL;
+ data->lock = FALSE;
+ }
if (data->callbacks)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- name_listeners = g_slist_remove(name_listeners, data);
- name_data_free(data);
+ remove_match(data);
+
+ listeners = g_slist_remove(listeners, data);
+ filter_data_free(data);
/* Remove filter if there no listener left for the connection */
- data = name_data_find(connection, NULL);
+ data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
if (!data)
- dbus_connection_remove_filter(connection, name_exit_filter,
+ dbus_connection_remove_filter(connection, message_filter,
NULL);
- remove_match(connection, name);
-
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
+struct service_data {
+ DBusConnection *conn;
+ GDBusWatchFunction conn_func;
+ void *user_data;
+};
+
+static void service_reply(DBusPendingCall *call, void *user_data)
+{
+ struct service_data *data = user_data;
+ DBusMessage *reply;
+ DBusError error;
+ dbus_bool_t has_owner;
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (reply == NULL)
+ return;
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error,
+ DBUS_TYPE_BOOLEAN, &has_owner,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ error("%s", error.message);
+ dbus_error_free(&error);
+ } else {
+ error("Wrong arguments for NameHasOwner reply");
+ }
+ goto done;
+ }
+
+ if (has_owner && data->conn_func)
+ data->conn_func(data->conn, data->user_data);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void check_service(DBusConnection *connection, const char *name,
+ GDBusWatchFunction connect, void *user_data)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+ struct service_data *data;
+
+ data = g_try_malloc0(sizeof(*data));
+ if (data == NULL) {
+ error("Can't allocate data structure");
+ return;
+ }
+
+ data->conn = connection;
+ data->conn_func = connect;
+ data->user_data = user_data;
+
+ message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner");
+ if (message == NULL) {
+ error("Can't allocate new message");
+ g_free(data);
+ return;
+ }
+
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, -1) == FALSE) {
+ error("Failed to execute method call");
+ g_free(data);
+ goto done;
+ }
+
+ if (call == NULL) {
+ error("D-Bus connection not available");
+ g_free(data);
+ goto done;
+ }
+
+ dbus_pending_call_set_notify(call, service_reply, data, NULL);
+
+ dbus_pending_call_unref(call);
+
+done:
+ dbus_message_unref(message);
+}
+
guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
GDBusWatchFunction connect,
GDBusWatchFunction disconnect,
void *user_data, GDBusDestroyFunction destroy)
{
- int first;
+ struct filter_data *data;
+ struct filter_callback *cb;
- if (!name_data_find(connection, NULL)) {
- if (!dbus_connection_add_filter(connection,
- name_exit_filter, NULL, NULL)) {
- error("dbus_connection_add_filter() failed");
- return 0;
- }
- }
+ if (!name)
+ return 0;
- listener_id++;
- first = name_data_add(connection, name, connect, disconnect,
- user_data, listener_id);
- /* The filter is already added if this is not the first callback
- * registration for the name */
- if (!first)
- return listener_id;
+ data = filter_data_get(connection, service_filter, NULL, NULL,
+ DBUS_INTERFACE_DBUS, "NameOwnerChanged",
+ name);
+ if (!data)
+ return 0;
- if (name) {
- debug("name_listener_add(%s)", name);
+ cb = filter_data_add_callback(data, connect, disconnect, NULL, NULL,
+ user_data);
+ if (!cb)
+ return 0;
- if (!add_match(connection, name)) {
- name_data_remove(connection, name, listener_id);
- return 0;
- }
- }
+ if (connect)
+ check_service(connection, name, connect, user_data);
- return listener_id;
+ return cb->id;
}
guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
@@ -351,72 +578,57 @@
}
guint g_dbus_add_signal_watch(DBusConnection *connection,
- const char *rule, GDBusSignalFunction function,
- void *user_data, GDBusDestroyFunction destroy)
+ const char *sender, const char *path,
+ const char *interface, const char *member,
+ GDBusSignalFunction function, void *user_data,
+ GDBusDestroyFunction destroy)
{
- return 0;
+ struct filter_data *data;
+ struct filter_callback *cb;
+
+ data = filter_data_get(connection, signal_filter, sender, path,
+ interface, member, NULL);
+ if (!data)
+ return 0;
+
+ cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
+ user_data);
+ if (!cb)
+ return 0;
+
+ return cb->id;
}
gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
{
- struct name_data *data;
- struct name_callback *cb;
- GSList *ldata, *lcb;
+ struct filter_data *data;
+ struct filter_callback *cb;
+ GSList *ldata;
if (id == 0)
return FALSE;
- for (ldata = name_listeners; ldata; ldata = ldata->next) {
+ for (ldata = listeners; ldata; ldata = ldata->next) {
data = ldata->data;
- for (lcb = data->callbacks; lcb; lcb = lcb->next) {
- cb = lcb->data;
- if (cb->id == id)
- goto remove;
- }
- for (lcb = data->processed; lcb; lcb = lcb->next) {
- cb = lcb->data;
- if (cb->id == id)
- goto remove;
+
+ cb = filter_data_find_callback(data, id);
+ if (cb) {
+ filter_data_remove_callback(data, cb);
+ return TRUE;
}
}
return FALSE;
-
-remove:
- data->callbacks = g_slist_remove(data->callbacks, cb);
- data->processed = g_slist_remove(data->processed, cb);
- g_free(cb);
-
- /* Don't remove the filter if other callbacks exist or data is lock
- * processing callbacks */
- if (data->callbacks || data->lock)
- return TRUE;
-
- if (data->name) {
- if (!remove_match(data->connection, data->name))
- return FALSE;
- }
-
- name_listeners = g_slist_remove(name_listeners, data);
- name_data_free(data);
-
- /* Remove filter if there are no listeners left for the connection */
- data = name_data_find(connection, NULL);
- if (!data)
- dbus_connection_remove_filter(connection, name_exit_filter,
- NULL);
-
- return TRUE;
}
void g_dbus_remove_all_watches(DBusConnection *connection)
{
- struct name_data *data;
+ struct filter_data *data;
- while ((data = name_data_find(connection, NULL))) {
- name_listeners = g_slist_remove(name_listeners, data);
- name_data_call_and_free(data);
+ while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL))) {
+ listeners = g_slist_remove(listeners, data);
+ filter_data_call_and_free(data);
}
- dbus_connection_remove_filter(connection, name_exit_filter, NULL);
+ dbus_connection_remove_filter(connection, message_filter, NULL);
}
diff --git a/include/bluetooth/Makefile.am b/include/bluetooth/Makefile.am
deleted file mode 100644
index 992e987..0000000
--- a/include/bluetooth/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-
-includedir = @includedir@/bluetooth
-
-include_HEADERS = \
- bluetooth.h hci.h hci_lib.h sco.h l2cap.h \
- sdp.h sdp_lib.h rfcomm.h bnep.h cmtp.h hidp.h
-
-MAINTAINERCLEANFILES = Makefile.in
-
-all-local:
- @if [ ! -e bluetooth ] ; then $(LN_S) $(top_srcdir)/include bluetooth ; fi
-
-clean-local:
- @rm -f bluetooth
diff --git a/input/Android.mk b/input/Android.mk
index 935afb9..8f8f4f5 100755
--- a/input/Android.mk
+++ b/input/Android.mk
@@ -12,13 +12,12 @@
server.c
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" \
+ -DVERSION=\"4.69\" \
-DSTORAGEDIR=\"/data/misc/bluetoothd\" \
-DCONFIGDIR=\"/etc/bluetooth\"
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
$(LOCAL_PATH)/../src \
$(LOCAL_PATH)/../gdbus \
$(call include-path-for, glib) \
diff --git a/input/Makefile.am b/input/Makefile.am
deleted file mode 100644
index 98ce928..0000000
--- a/input/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-
-if INPUTPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = input.la
-
-input_la_SOURCES = main.c manager.h manager.c \
- server.h server.c device.h device.c \
- fakehid.c fakehid.h
-
-LDADD = $(top_builddir)/common/libhelper.a \
- @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden \
- @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = input.conf sixpair.c
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/input/device.c b/input/device.c
index 2cfc5d8..f06b229 100644
--- a/input/device.c
+++ b/input/device.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -46,7 +46,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "uinput.h"
@@ -298,7 +298,7 @@
goto failed;
}
- debug("Received: %s", buf);
+ DBG("Received: %s", buf);
if (g_io_channel_write(chan, ok, 6, &bwritten) != G_IO_ERROR_NONE) {
error("IO Channel write error");
@@ -596,8 +596,7 @@
close(req->ctrl_sock);
cleanup:
- if (req->rd_data)
- free(req->rd_data);
+ free(req->rd_data);
g_free(req);
}
@@ -659,17 +658,10 @@
}
}
- if (req->vendor == 0x054c && req->product == 0x0268) {
- unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 };
- int sk = g_io_channel_unix_get_fd(iconn->ctrl_io);
- err = write(sk, buf, sizeof(buf));
- }
-
err = ioctl_connadd(req);
cleanup:
- if (req->rd_data)
- free(req->rd_data);
+ free(req->rd_data);
g_free(req);
return err;
@@ -892,6 +884,7 @@
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);
@@ -970,6 +963,7 @@
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;
}
@@ -1008,7 +1002,7 @@
{
struct input_device *idev = data;
- debug("Unregistered interface %s on path %s", INPUT_DEVICE_INTERFACE,
+ DBG("Unregistered interface %s on path %s", INPUT_DEVICE_INTERFACE,
idev->path);
devices = g_slist_remove(devices, idev);
@@ -1095,7 +1089,7 @@
return NULL;
}
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
INPUT_DEVICE_INTERFACE, idev->path);
return idev;
diff --git a/input/device.h b/input/device.h
index f9ec7c2..3390a0b 100644
--- a/input/device.h
+++ b/input/device.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/input/fakehid.c b/input/fakehid.c
index 6c9a715..ee1f77a 100644
--- a/input/fakehid.c
+++ b/input/fakehid.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@
#include "../src/adapter.h"
#include "../src/device.h"
-#include "logging.h"
+#include "log.h"
#include "device.h"
#include "fakehid.h"
#include "uinput.h"
diff --git a/input/fakehid.h b/input/fakehid.h
index 90aacb4..33b1e70 100644
--- a/input/fakehid.h
+++ b/input/fakehid.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/input/main.c b/input/main.c
index 913ea7b..e165ab4 100644
--- a/input/main.c
+++ b/input/main.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@
#include <gdbus.h>
#include "plugin.h"
-#include "logging.h"
+#include "log.h"
#include "manager.h"
static GKeyFile *load_config_file(const char *file)
diff --git a/input/manager.c b/input/manager.c
index 567075b..a98a080 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "../src/adapter.h"
#include "../src/device.h"
@@ -45,7 +45,7 @@
static int idle_timeout = 0;
static DBusConnection *connection = NULL;
-GSList *adapters = NULL;
+static GSList *adapters = NULL;
static void input_remove(struct btd_device *device, const char *uuid)
{
@@ -179,7 +179,7 @@
idle_timeout = g_key_file_get_integer(config, "General",
"IdleTimeout", &err);
if (err) {
- debug("input.conf: %s", err->message);
+ DBG("input.conf: %s", err->message);
g_error_free(err);
}
}
diff --git a/input/manager.h b/input/manager.h
index 754c57a..7b93c5b 100644
--- a/input/manager.h
+++ b/input/manager.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/input/server.c b/input/server.c
index 5ae9f8c..d98018b 100644
--- a/input/server.c
+++ b/input/server.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#include <glib.h>
#include <dbus/dbus.h>
-#include "logging.h"
+#include "log.h"
#include "glib-helper.h"
#include "btio.h"
@@ -82,7 +82,7 @@
return;
}
- debug("Incoming connection on PSM %d", psm);
+ DBG("Incoming connection on PSM %d", psm);
ret = input_device_set_channel(&src, &dst, psm, chan);
if (ret == 0)
@@ -187,6 +187,7 @@
server, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, src,
BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
BT_IO_OPT_INVALID);
if (!server->ctrl) {
error("Failed to listen on control channel");
@@ -199,6 +200,7 @@
server, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, src,
BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
BT_IO_OPT_INVALID);
if (!server->intr) {
error("Failed to listen on interrupt channel");
diff --git a/input/server.h b/input/server.h
index c3dee07..74159bb 100644
--- a/input/server.h
+++ b/input/server.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/lib/Android.mk b/lib/Android.mk
index a0dc4d0..0d645aa 100755
--- a/lib/Android.mk
+++ b/lib/Android.mk
@@ -6,8 +6,8 @@
sdp.c \
hci.c
-LOCAL_C_INCLUDES+= \
- $(LOCAL_PATH)/../include/
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/bluetooth \
LOCAL_MODULE:=libbluetooth
diff --git a/lib/Makefile.am b/lib/Makefile.am
deleted file mode 100644
index f7a8ffb..0000000
--- a/lib/Makefile.am
+++ /dev/null
@@ -1,9 +0,0 @@
-
-lib_LTLIBRARIES = libbluetooth.la
-
-libbluetooth_la_SOURCES = bluetooth.c hci.c sdp.c
-libbluetooth_la_LDFLAGS = -version-info 5:7:2
-
-INCLUDES = -I$(top_builddir)/include
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/lib/bluetooth.c b/lib/bluetooth.c
index 1c34f25..4ed03e9 100644
--- a/lib/bluetooth.c
+++ b/lib/bluetooth.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -35,8 +35,8 @@
#include <string.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "bluetooth.h"
+#include "hci.h"
void baswap(bdaddr_t *dst, const bdaddr_t *src)
{
@@ -55,7 +55,7 @@
return NULL;
sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
- ba->b[0], ba->b[1], ba->b[2],
+ ba->b[0], ba->b[1], ba->b[2],
ba->b[3], ba->b[4], ba->b[5]);
return str;
@@ -429,7 +429,7 @@
case 70:
return "MediaTek, Inc.";
case 71:
- return "Bluegiga"; /* (tentative) */
+ return "Bluegiga";
case 72:
return "Marvell Technology Group Ltd.";
case 73:
@@ -462,6 +462,24 @@
return "Sony Ericsson Mobile Communications";
case 87:
return "Harman International Industries, Inc.";
+ case 88:
+ return "Vizio, Inc.";
+ case 89:
+ return "Nordic Semiconductor ASA";
+ case 90:
+ return "EM Microelectronic-Marin SA";
+ case 91:
+ return "Ralink Technology Corporation";
+ case 92:
+ return "Belkin International, Inc.";
+ case 93:
+ return "Realtek Semiconductor Corporation";
+ case 94:
+ return "Stonestreet One, LLC";
+ case 95:
+ return "Wicentric, Inc.";
+ case 96:
+ return "RivieraWaves S.A.S";
case 65535:
return "internal use";
default:
diff --git a/include/bluetooth/bluetooth.h b/lib/bluetooth/bluetooth.h
similarity index 98%
rename from include/bluetooth/bluetooth.h
rename to lib/bluetooth/bluetooth.h
index b0b23a4..a0486c7 100644
--- a/include/bluetooth/bluetooth.h
+++ b/lib/bluetooth/bluetooth.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/bnep.h b/lib/bluetooth/bnep.h
similarity index 97%
rename from include/bluetooth/bnep.h
rename to lib/bluetooth/bnep.h
index a022c8e..2bbfb17 100644
--- a/include/bluetooth/bnep.h
+++ b/lib/bluetooth/bnep.h
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/cmtp.h b/lib/bluetooth/cmtp.h
similarity index 95%
rename from include/bluetooth/cmtp.h
rename to lib/bluetooth/cmtp.h
index b7439ac..ce937bd 100644
--- a/include/bluetooth/cmtp.h
+++ b/lib/bluetooth/cmtp.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/hci.h b/lib/bluetooth/hci.h
similarity index 84%
rename from include/bluetooth/hci.h
rename to lib/bluetooth/hci.h
index aaee296..57b6150 100644
--- a/include/bluetooth/hci.h
+++ b/lib/bluetooth/hci.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@
#define HCI_DEV_SUSPEND 5
#define HCI_DEV_RESUME 6
-/* HCI device types */
+/* HCI bus types */
#define HCI_VIRTUAL 0
#define HCI_USB 1
#define HCI_PCCARD 2
@@ -56,6 +56,10 @@
#define HCI_PCI 5
#define HCI_SDIO 6
+/* HCI controller types */
+#define HCI_BREDR 0x00
+#define HCI_80211 0x01
+
/* HCI device flags */
enum {
HCI_UP,
@@ -93,6 +97,9 @@
#define HCISETACLMTU _IOW('H', 227, int)
#define HCISETSCOMTU _IOW('H', 228, int)
+#define HCIBLOCKADDR _IOW('H', 230, int)
+#define HCIUNBLOCKADDR _IOW('H', 231, int)
+
#define HCIINQUIRY _IOR('H', 240, int)
#ifndef __NO_HCI_DEFS
@@ -253,6 +260,8 @@
#define LMP_EV5 0x02
#define LMP_AFH_CAP_SLV 0x08
#define LMP_AFH_CLS_SLV 0x10
+#define LMP_NO_BREDR 0x20
+#define LMP_LE 0x40
#define LMP_EDR_3SLOT 0x80
#define LMP_EDR_5SLOT 0x01
@@ -265,6 +274,7 @@
#define LMP_EDR_3S_ESCO 0x80
#define LMP_EXT_INQ 0x01
+#define LMP_LE_BREDR 0x02
#define LMP_SIMPLE_PAIR 0x08
#define LMP_ENCAPS_PDU 0x10
#define LMP_ERR_DAT_REP 0x20
@@ -272,6 +282,7 @@
#define LMP_LSTO 0x01
#define LMP_INQ_TX_PWR 0x02
+#define LMP_EPC 0x04
#define LMP_EXT_FEAT 0x80
/* Link policies */
@@ -742,14 +753,14 @@
typedef struct {
uint8_t name[248];
} __attribute__ ((packed)) change_local_name_cp;
-#define CHANGE_LOCAL_NAME_CP_SIZE 248
+#define CHANGE_LOCAL_NAME_CP_SIZE 248
#define OCF_READ_LOCAL_NAME 0x0014
typedef struct {
uint8_t status;
uint8_t name[248];
} __attribute__ ((packed)) read_local_name_rp;
-#define READ_LOCAL_NAME_RP_SIZE 249
+#define READ_LOCAL_NAME_RP_SIZE 249
#define OCF_READ_CONN_ACCEPT_TIMEOUT 0x0015
typedef struct {
@@ -837,7 +848,7 @@
uint8_t status;
uint8_t dev_class[3];
} __attribute__ ((packed)) read_class_of_dev_rp;
-#define READ_CLASS_OF_DEV_RP_SIZE 4
+#define READ_CLASS_OF_DEV_RP_SIZE 4
#define OCF_WRITE_CLASS_OF_DEV 0x0024
typedef struct {
@@ -1070,6 +1081,13 @@
} __attribute__ ((packed)) read_local_oob_data_rp;
#define READ_LOCAL_OOB_DATA_RP_SIZE 33
+#define OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL 0x0058
+typedef struct {
+ uint8_t status;
+ int8_t level;
+} __attribute__ ((packed)) read_inq_response_tx_power_level_rp;
+#define READ_INQ_RESPONSE_TX_POWER_LEVEL_RP_SIZE 2
+
#define OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL 0x0058
typedef struct {
uint8_t status;
@@ -1258,6 +1276,250 @@
} __attribute__ ((packed)) write_simple_pairing_debug_mode_rp;
#define WRITE_SIMPLE_PAIRING_DEBUG_MODE_RP_SIZE 1
+/* LE commands */
+#define OGF_LE_CTL 0x08
+
+#define OCF_LE_SET_EVENT_MASK 0x0001
+typedef struct {
+ uint8_t mask[8];
+} __attribute__ ((packed)) le_set_event_mask_cp;
+#define LE_SET_EVENT_MASK_CP_SIZE 8
+
+#define OCF_LE_READ_BUFFER_SIZE 0x0002
+typedef struct {
+ uint8_t status;
+ uint16_t pkt_len;
+ uint8_t max_pkt;
+} __attribute__ ((packed)) le_read_buffer_size_rp;
+#define LE_READ_BUFFER_SIZE_RP_SIZE 4
+
+#define OCF_LE_READ_LOCAL_SUPPORTED_FEATURES 0x0003
+typedef struct {
+ uint8_t status;
+ uint8_t features[8];
+} __attribute__ ((packed)) le_read_local_supported_features_rp;
+#define LE_READ_LOCAL_SUPPORTED_FEATURES_RP_SIZE 9
+
+#define OCF_LE_SET_RANDOM_ADDRESS 0x0005
+typedef struct {
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) le_set_random_address_cp;
+#define LE_SET_RANDOM_ADDRESS_CP_SIZE 6
+
+#define OCF_LE_SET_ADVERTISING_PARAMETERS 0x0006
+typedef struct {
+ uint16_t min_interval;
+ uint16_t max_interval;
+ uint8_t advtype;
+ uint8_t own_bdaddr_type;
+ uint8_t direct_bdaddr_type;
+ bdaddr_t direct_bdaddr;
+ uint8_t chan_map;
+ uint8_t filter;
+} __attribute__ ((packed)) le_set_advertising_parameters_cp;
+#define LE_SET_ADVERTISING_PARAMETERS_CP_SIZE 15
+
+#define OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER 0x0007
+typedef struct {
+ uint8_t status;
+ uint8_t level;
+} __attribute__ ((packed)) le_read_advertising_channel_tx_power_rp;
+#define LE_READ_ADVERTISING_CHANNEL_TX_POWER_RP_SIZE 2
+
+#define OCF_LE_SET_ADVERTISING_DATA 0x0008
+typedef struct {
+ uint8_t length;
+ uint8_t data[31];
+} __attribute__ ((packed)) le_set_advertising_data_cp;
+#define LE_SET_ADVERTISING_DATA_CP_SIZE 32
+
+#define OCF_LE_SET_SCAN_RESPONSE_DATA 0x0009
+typedef struct {
+ uint8_t length;
+ uint8_t data[31];
+} __attribute__ ((packed)) le_set_scan_response_data_cp;
+#define LE_SET_SCAN_RESPONSE_DATA_CP_SIZE 32
+
+#define OCF_LE_SET_ADVERTISE_ENABLE 0x000A
+typedef struct {
+ uint8_t enable;
+} __attribute__ ((packed)) le_set_advertise_enable_cp;
+#define LE_SET_ADVERTISE_ENABLE_CP_SIZE 1
+
+#define OCF_LE_SET_SCAN_PARAMETERS 0x000B
+typedef struct {
+ uint8_t type;
+ uint16_t interval;
+ uint16_t window;
+ uint8_t own_bdaddr_type;
+ uint8_t filter;
+} __attribute__ ((packed)) le_set_scan_parameters_cp;
+#define LE_SET_SCAN_PARAMETERS_CP_SIZE 7
+
+#define OCF_LE_SET_SCAN_ENABLE 0x000C
+typedef struct {
+ uint8_t enable;
+ uint8_t filter_dup;
+} __attribute__ ((packed)) le_set_scan_enable_cp;
+#define LE_SET_SCAN_ENABLE_CP_SIZE 2
+
+#define OCF_LE_CREATE_CONN 0x000D
+typedef struct {
+ uint16_t interval;
+ uint16_t window;
+ uint8_t initiator_filter;
+ uint8_t peer_bdaddr_type;
+ bdaddr_t peer_bdaddr;
+ uint8_t own_bdaddr_type;
+ uint16_t min_interval;
+ uint16_t max_interval;
+ uint16_t latency;
+ uint16_t supervision_timeout;
+ uint16_t min_ce_length;
+ uint16_t max_ce_length;
+} __attribute__ ((packed)) le_create_connection_cp;
+#define LE_CREATE_CONN_CP_SIZE 25
+
+#define OCF_LE_CREATE_CONN_CANCEL 0x000E
+
+#define OCF_LE_READ_WHITE_LIST_SIZE 0x000F
+typedef struct {
+ uint8_t status;
+ uint8_t size;
+} __attribute__ ((packed)) le_read_white_list_size_rp;
+#define LE_READ_WHITE_LIST_SIZE_RP_SIZE 2
+
+#define OCF_LE_CLEAR_WHITE_LIST 0x0010
+
+#define OCF_LE_ADD_DEVICE_TO_WHITE_LIST 0x0011
+typedef struct {
+ uint8_t bdaddr_type;
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) le_add_device_to_white_list_cp;
+#define LE_ADD_DEVICE_TO_WHITE_LIST_CP_SIZE 7
+
+#define OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST 0x0012
+typedef struct {
+ uint8_t bdaddr_type;
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) le_remove_device_from_white_list_cp;
+#define LE_REMOVE_DEVICE_FROM_WHITE_LIST_CP_SIZE 7
+
+#define OCF_LE_CONN_UPDATE 0x0013
+typedef struct {
+ uint16_t handle;
+ uint16_t min_interval;
+ uint16_t max_interval;
+ uint16_t latency;
+ uint16_t supervision_timeout;
+ uint16_t min_ce_length;
+ uint16_t max_ce_length;
+} __attribute__ ((packed)) le_connection_update_cp;
+#define LE_CONN_UPDATE_CP_SIZE 14
+
+#define OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION 0x0014
+typedef struct {
+ uint8_t map[5];
+} __attribute__ ((packed)) le_set_host_channel_classification_cp;
+#define LE_SET_HOST_CHANNEL_CLASSIFICATION_CP_SIZE 5
+
+#define OCF_LE_READ_CHANNEL_MAP 0x0015
+typedef struct {
+ uint16_t handle;
+} __attribute__ ((packed)) le_read_channel_map_cp;
+#define LE_READ_CHANNEL_MAP_CP_SIZE 2
+typedef struct {
+ uint8_t status;
+ uint16_t handle;
+ uint8_t map[5];
+} __attribute__ ((packed)) le_read_channel_map_rp;
+#define LE_READ_CHANNEL_MAP_RP_SIZE 8
+
+#define OCF_LE_READ_REMOTE_USED_FEATURES 0x0016
+typedef struct {
+ uint16_t handle;
+} __attribute__ ((packed)) le_read_remote_used_features_cp;
+#define LE_READ_REMOTE_USED_FEATURES_CP_SIZE 2
+
+#define OCF_LE_ENCRYPT 0x0017
+typedef struct {
+ uint8_t key[16];
+ uint8_t plaintext[16];
+} __attribute__ ((packed)) le_encrypt_cp;
+#define LE_ENCRYPT_CP_SIZE 32
+typedef struct {
+ uint8_t status;
+ uint8_t data[16];
+} __attribute__ ((packed)) le_encrypt_rp;
+#define LE_ENCRYPT_RP_SIZE 17
+
+#define OCF_LE_RAND 0x0018
+typedef struct {
+ uint8_t status;
+ uint64_t random;
+} __attribute__ ((packed)) le_rand_rp;
+#define LE_RAND_RP_SIZE 9
+
+#define OCF_LE_START_ENCRYPTION 0x0019
+typedef struct {
+ uint16_t handle;
+ uint64_t random;
+ uint16_t diversifier;
+ uint8_t key[16];
+} __attribute__ ((packed)) le_start_encryption_cp;
+#define LE_START_ENCRYPTION_CP_SIZE 28
+
+#define OCF_LE_LTK_REPLY 0x001A
+typedef struct {
+ uint16_t handle;
+ uint8_t key[16];
+} __attribute__ ((packed)) le_ltk_reply_cp;
+#define LE_LTK_REPLY_CP_SIZE 18
+typedef struct {
+ uint8_t status;
+ uint16_t handle;
+} __attribute__ ((packed)) le_ltk_reply_rp;
+#define LE_LTK_REPLY_RP_SIZE 3
+
+#define OCF_LE_LTK_NEG_REPLY 0x001B
+typedef struct {
+ uint16_t handle;
+} __attribute__ ((packed)) le_ltk_neg_reply_cp;
+#define LE_LTK_NEG_REPLY_CP_SIZE 2
+typedef struct {
+ uint8_t status;
+ uint16_t handle;
+} __attribute__ ((packed)) le_ltk_neg_reply_rp;
+#define LE_LTK_NEG_REPLY_RP_SIZE 3
+
+#define OCF_LE_READ_SUPPORTED_STATES 0x001C
+typedef struct {
+ uint8_t status;
+ uint64_t states;
+} __attribute__ ((packed)) le_read_supported_states_rp;
+#define LE_READ_SUPPORTED_STATES_RP_SIZE 9
+
+#define OCF_LE_RECEIVER_TEST 0x001D
+typedef struct {
+ uint8_t frequency;
+} __attribute__ ((packed)) le_receiver_test_cp;
+#define LE_RECEIVER_TEST_CP_SIZE 1
+
+#define OCF_LE_TRANSMITTER_TEST 0x001E
+typedef struct {
+ uint8_t frequency;
+ uint8_t length;
+ uint8_t payload;
+} __attribute__ ((packed)) le_transmitter_test_cp;
+#define LE_TRANSMITTER_TEST_CP_SIZE 3
+
+#define OCF_LE_TEST_END 0x001F
+typedef struct {
+ uint8_t status;
+ uint16_t num_pkts;
+} __attribute__ ((packed)) le_test_end_rp;
+#define LE_TEST_END_RP_SIZE 3
+
/* Vendor specific commands */
#define OGF_VENDOR_CMD 0x3f
@@ -1660,6 +1922,64 @@
} __attribute__ ((packed)) evt_remote_host_features_notify;
#define EVT_REMOTE_HOST_FEATURES_NOTIFY_SIZE 14
+#define EVT_LE_META_EVENT 0x3E
+typedef struct {
+ uint8_t subevent;
+ uint8_t data[0];
+} __attribute__ ((packed)) evt_le_meta_event;
+#define EVT_LE_META_EVENT_SIZE 1
+
+#define EVT_LE_CONN_COMPLETE 0x01
+typedef struct {
+ uint8_t status;
+ uint16_t handle;
+ uint8_t role;
+ uint8_t peer_bdaddr_type;
+ bdaddr_t peer_bdaddr;
+ uint16_t interval;
+ uint16_t latency;
+ uint16_t supervision_timeout;
+ uint8_t master_clock_accuracy;
+} __attribute__ ((packed)) evt_le_connection_complete;
+#define EVT_LE_CONN_COMPLETE_SIZE 18
+
+#define EVT_LE_ADVERTISING_REPORT 0x02
+typedef struct {
+ uint8_t evt_type;
+ uint8_t bdaddr_type;
+ bdaddr_t bdaddr;
+ uint8_t length;
+ uint8_t data[31];
+ uint8_t rssi;
+} __attribute__ ((packed)) le_advertising_info;
+#define LE_ADVERTISING_INFO_SIZE 41
+
+#define EVT_LE_CONN_UPDATE_COMPLETE 0x03
+typedef struct {
+ uint8_t status;
+ uint16_t handle;
+ uint16_t interval;
+ uint16_t latency;
+ uint16_t supervision_timeout;
+} __attribute__ ((packed)) evt_le_connection_update_complete;
+#define EVT_LE_CONN_UPDATE_COMPLETE_SIZE 9
+
+#define EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04
+typedef struct {
+ uint8_t status;
+ uint16_t handle;
+ uint8_t features[8];
+} __attribute__ ((packed)) evt_le_read_remote_used_features_complete;
+#define EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE_SIZE 11
+
+#define EVT_LE_LTK_REQUEST 0x05
+typedef struct {
+ uint16_t handle;
+ uint64_t random;
+ uint16_t diversifier;
+} __attribute__ ((packed)) evt_le_long_term_key_request;
+#define EVT_LE_LTK_REQUEST_SIZE 12
+
#define EVT_TESTING 0xFE
#define EVT_VENDOR 0xFF
diff --git a/include/bluetooth/hci_lib.h b/lib/bluetooth/hci_lib.h
similarity index 91%
rename from include/bluetooth/hci_lib.h
rename to lib/bluetooth/hci_lib.h
index bd50785..b63a2a4 100644
--- a/include/bluetooth/hci_lib.h
+++ b/lib/bluetooth/hci_lib.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -101,6 +101,7 @@
int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to);
int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to);
int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to);
+int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to);
int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to);
int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to);
int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to);
@@ -114,9 +115,24 @@
int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to);
int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to);
+int hci_le_set_scan_enable(int dev_id, uint8_t enable, uint8_t filter_dup);
+int hci_le_set_scan_parameters(int dev_id, uint8_t type, uint16_t interval,
+ uint16_t window, uint8_t own_type,
+ uint8_t filter);
+int hci_le_set_advertise_enable(int dev_id, uint8_t enable);
+int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
+ uint8_t initiator_filter, uint8_t peer_bdaddr_type,
+ bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
+ uint16_t min_interval, uint16_t max_interval,
+ uint16_t latency, uint16_t supervision_timeout,
+ uint16_t min_ce_length, uint16_t max_ce_length,
+ uint16_t *handle, int to);
+
int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg);
int hci_get_route(bdaddr_t *bdaddr);
+char *hci_bustostr(int bus);
+char *hci_typetostr(int type);
char *hci_dtypetostr(int type);
char *hci_dflagstostr(uint32_t flags);
char *hci_ptypetostr(unsigned int ptype);
diff --git a/include/bluetooth/hidp.h b/lib/bluetooth/hidp.h
similarity index 96%
rename from include/bluetooth/hidp.h
rename to lib/bluetooth/hidp.h
index 7ae56c8..c5e6a78 100644
--- a/include/bluetooth/hidp.h
+++ b/lib/bluetooth/hidp.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/l2cap.h b/lib/bluetooth/l2cap.h
similarity index 97%
rename from include/bluetooth/l2cap.h
rename to lib/bluetooth/l2cap.h
index be2bebf..17ad554 100644
--- a/include/bluetooth/l2cap.h
+++ b/lib/bluetooth/l2cap.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -51,6 +51,9 @@
uint16_t imtu;
uint16_t flush_to;
uint8_t mode;
+ uint8_t fcs;
+ uint8_t max_tx;
+ uint16_t txwin_size;
};
#define L2CAP_CONNINFO 0x02
diff --git a/include/bluetooth/rfcomm.h b/lib/bluetooth/rfcomm.h
similarity index 96%
rename from include/bluetooth/rfcomm.h
rename to lib/bluetooth/rfcomm.h
index 0765af3..ad6c0e1 100644
--- a/include/bluetooth/rfcomm.h
+++ b/lib/bluetooth/rfcomm.h
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/sco.h b/lib/bluetooth/sco.h
similarity index 95%
rename from include/bluetooth/sco.h
rename to lib/bluetooth/sco.h
index ff71829..82cd77c 100644
--- a/include/bluetooth/sco.h
+++ b/lib/bluetooth/sco.h
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/sdp.h b/lib/bluetooth/sdp.h
similarity index 94%
rename from include/bluetooth/sdp.h
rename to lib/bluetooth/sdp.h
index 63cfcf0..2e1f6b5 100644
--- a/include/bluetooth/sdp.h
+++ b/lib/bluetooth/sdp.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -141,9 +141,9 @@
#define VIDEO_SOURCE_SVCLASS_ID 0x1303
#define VIDEO_SINK_SVCLASS_ID 0x1304
#define VIDEO_DISTRIBUTION_SVCLASS_ID 0x1305
-#define MDP_SVCLASS_ID 0x1400
-#define MDP_SOURCE_SVCLASS_ID 0x1401
-#define MDP_SINK_SVCLASS_ID 0x1402
+#define HDP_SVCLASS_ID 0x1400
+#define HDP_SOURCE_SVCLASS_ID 0x1401
+#define HDP_SINK_SVCLASS_ID 0x1402
#define APPLE_AGENT_SVCLASS_ID 0x2112
/*
@@ -213,12 +213,22 @@
#define VIDEO_SOURCE_PROFILE_ID VIDEO_SOURCE_SVCLASS_ID
#define VIDEO_SINK_PROFILE_ID VIDEO_SINK_SVCLASS_ID
#define VIDEO_DISTRIBUTION_PROFILE_ID VIDEO_DISTRIBUTION_SVCLASS_ID
-#define MDP_PROFILE_ID MDP_SVCLASS_ID
-#define MDP_SOURCE_PROFILE_ID MDP_SROUCE_SVCLASS_ID
-#define MDP_SINK_PROFILE_ID MDP_SINK_SVCLASS_ID
+#define HDP_PROFILE_ID HDP_SVCLASS_ID
+#define HDP_SOURCE_PROFILE_ID HDP_SOURCE_SVCLASS_ID
+#define HDP_SINK_PROFILE_ID HDP_SINK_SVCLASS_ID
#define APPLE_AGENT_PROFILE_ID APPLE_AGENT_SVCLASS_ID
/*
+ * Compatibility macros for the old MDP acronym
+ */
+#define MDP_SVCLASS_ID HDP_SVCLASS_ID
+#define MDP_SOURCE_SVCLASS_ID HDP_SOURCE_SVCLASS_ID
+#define MDP_SINK_SVCLASS_ID HDP_SINK_SVCLASS_ID
+#define MDP_PROFILE_ID HDP_PROFILE_ID
+#define MDP_SOURCE_PROFILE_ID HDP_SOURCE_PROFILE_ID
+#define MDP_SINK_PROFILE_ID HDP_SINK_PROFILE_ID
+
+/*
* Attribute identifier codes
*/
#define SDP_SERVER_RECORD_HANDLE 0x0000
@@ -245,13 +255,16 @@
#define SDP_ATTR_GROUP_ID 0x0200
#define SDP_ATTR_IP_SUBNET 0x0200
#define SDP_ATTR_VERSION_NUM_LIST 0x0200
+#define SDP_ATTR_SUPPORTED_FEATURES_LIST 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_FAX_CLASS1_SUPPORT 0x0302
#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
+#define SDP_ATTR_MCAP_SUPPORTED_PROCEDURES 0x0302
#define SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303
#define SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303
#define SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304
@@ -295,7 +308,7 @@
#define SDP_ATTR_HID_BOOT_DEVICE 0x020e
/*
- * These identifiers are based on the SDP spec stating that
+ * These identifiers are based on the SDP spec stating that
* "base attribute id of the primary (universal) language must be 0x0100"
*
* Other languages should have their own offset; e.g.:
diff --git a/include/bluetooth/sdp_lib.h b/lib/bluetooth/sdp_lib.h
similarity index 91%
rename from include/bluetooth/sdp_lib.h
rename to lib/bluetooth/sdp_lib.h
index f3f4357..e506ac1 100644
--- a/include/bluetooth/sdp_lib.h
+++ b/lib/bluetooth/sdp_lib.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -47,7 +47,7 @@
sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *data, sdp_comp_func_t f);
void sdp_list_free(sdp_list_t *list, sdp_free_func_t f);
-static inline int sdp_list_len(const sdp_list_t *list)
+static inline int sdp_list_len(const sdp_list_t *list)
{
int n = 0;
for (; list; list = list->next)
@@ -118,9 +118,9 @@
/*
* create an L2CAP connection to a Bluetooth device
- *
+ *
* INPUT:
- *
+ *
* bdaddr_t *src:
* Address of the local device to use to make the connection
* (or BDADDR_ANY)
@@ -174,29 +174,29 @@
int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp);
/*
- * NOTE that none of the functions below will update the SDP server,
+ * NOTE that none of the functions below will update the SDP server,
* unless the {register, update}sdp_record_t() function is invoked.
- * All functions which return an integer value, return 0 on success
+ * All functions which return an integer value, return 0 on success
* or -1 on failure.
*/
/*
* Create an attribute and add it to the service record's attribute list.
- * This consists of the data type descriptor of the attribute,
+ * This consists of the data type descriptor of the attribute,
* the value of the attribute and the attribute identifier.
*/
int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *p);
/*
* Set the information attributes of the service record.
- * The set of attributes comprises service name, description
+ * The set of attributes comprises service name, description
* and provider name
*/
void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc);
/*
* Set the ServiceClassID attribute to the sequence specified by seq.
- * Note that the identifiers need to be in sorted order from the most
+ * Note that the identifiers need to be in sorted order from the most
* specific to the most generic service class that this service
* conforms to.
*/
@@ -207,8 +207,8 @@
/*
* Get the service classes to which the service conforms.
- *
- * When set, the list contains elements of ServiceClassIdentifer(uint16_t)
+ *
+ * When set, the list contains elements of ServiceClassIdentifer(uint16_t)
* ordered from most specific to most generic
*/
static inline int sdp_get_service_classes(const sdp_record_t *rec, sdp_list_t **seqp)
@@ -218,8 +218,8 @@
/*
* Set the BrowseGroupList attribute to the list specified by seq.
- *
- * A service can belong to one or more service groups
+ *
+ * A service can belong to one or more service groups
* and the list comprises such group identifiers (UUIDs)
*/
static inline int sdp_set_browse_groups(sdp_record_t *rec, sdp_list_t *seq)
@@ -238,24 +238,24 @@
int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
/*
- * Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM)
+ * Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM)
*/
int sdp_get_proto_port(const sdp_list_t *list, int proto);
/*
- * Get protocol descriptor.
+ * Get protocol descriptor.
*/
sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto);
/*
- * Set the LanguageBase attributes to the values specified in list
- * (a linked list of sdp_lang_attr_t objects, one for each language in
+ * Set the LanguageBase attributes to the values specified in list
+ * (a linked list of sdp_lang_attr_t objects, one for each language in
* which user-visible attributes are present).
*/
int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *list);
/*
- * Set the ServiceInfoTimeToLive attribute of the service.
+ * Set the ServiceInfoTimeToLive attribute of the service.
* This is the number of seconds that this record is guaranteed
* not to change after being obtained by a client.
*/
@@ -266,8 +266,8 @@
/*
* Set the ServiceRecordState attribute of a service. This is
- * guaranteed to change if there is any kind of modification to
- * the record.
+ * guaranteed to change if there is any kind of modification to
+ * the record.
*/
static inline int sdp_set_record_state(sdp_record_t *rec, uint32_t state)
{
@@ -275,7 +275,7 @@
}
/*
- * Set the ServiceID attribute of a service.
+ * Set the ServiceID attribute of a service.
*/
void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid);
@@ -286,7 +286,7 @@
/*
* Set the ServiceAvailability attribute of a service.
- *
+ *
* Note that this represents the relative availability
* of the service: 0x00 means completely unavailable;
* 0xFF means maximum availability.
@@ -298,7 +298,7 @@
/*
* Set the profile descriptor list attribute of a record.
- *
+ *
* Each element in the list is an object of type
* sdp_profile_desc_t which is a definition of the
* Bluetooth profile that this service conforms to.
@@ -307,41 +307,41 @@
/*
* Set URL attributes of a record.
- *
- * ClientExecutableURL: a URL to a client's platform specific (WinCE,
+ *
+ * ClientExecutableURL: a URL to a client's platform specific (WinCE,
* PalmOS) executable code that can be used to access this service.
- *
+ *
* DocumentationURL: a URL pointing to service documentation
- *
+ *
* IconURL: a URL to an icon that can be used to represent this service.
- *
+ *
* Note: pass NULL for any URLs that you don't want to set or remove
*/
void sdp_set_url_attr(sdp_record_t *rec, const char *clientExecURL, const char *docURL, const char *iconURL);
/*
- * a service search request.
- *
+ * a service search request.
+ *
* INPUT :
- *
+ *
* sdp_list_t *search
* list containing elements of the search
* pattern. Each entry in the list is a UUID
* of the service to be searched
- *
+ *
* uint16_t max_rec_num
* An integer specifying the maximum number of
* entries that the client can handle in the response.
- *
+ *
* OUTPUT :
- *
+ *
* int return value
- * 0
+ * 0
* The request completed successfully. This does not
* mean the requested services were found
* -1
* The request completed unsuccessfully
- *
+ *
* sdp_list_t *rsp_list
* This variable is set on a successful return if there are
* non-zero service handles. It is a singly linked list of
@@ -350,33 +350,33 @@
int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num, sdp_list_t **rsp_list);
/*
- * a service attribute request.
- *
+ * a service attribute request.
+ *
* INPUT :
- *
+ *
* uint32_t handle
* The handle of the service for which the attribute(s) are
* requested
- *
+ *
* sdp_attrreq_type_t reqtype
* Attribute identifiers are 16 bit unsigned integers specified
* in one of 2 ways described below :
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
* They are the actual attribute identifiers in ascending order
- *
+ *
* SDP_ATTR_REQ_RANGE - 32bit identifier range
* The high-order 16bits is the start of range
* the low-order 16bits are the end of range
* 0x0000 to 0xFFFF gets all attributes
- *
+ *
* sdp_list_t *attrid_list
* Singly linked list containing attribute identifiers desired.
- * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
- *
+ *
* OUTPUT :
* int return value
- * 0
+ * 0
* The request completed successfully. This does not
* mean the requested services were found
* -1
@@ -388,38 +388,38 @@
* This is a service search request combined with the service
* attribute request. First a service class match is done and
* for matching service, requested attributes are extracted
- *
+ *
* INPUT :
- *
+ *
* sdp_list_t *search
* Singly linked list containing elements of the search
* pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)
* of the service to be searched
- *
+ *
* AttributeSpecification attrSpec
* Attribute identifiers are 16 bit unsigned integers specified
* in one of 2 ways described below :
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
* They are the actual attribute identifiers in ascending order
- *
+ *
* SDP_ATTR_REQ_RANGE - 32bit identifier range
* The high-order 16bits is the start of range
* the low-order 16bits are the end of range
* 0x0000 to 0xFFFF gets all attributes
- *
+ *
* sdp_list_t *attrid_list
* Singly linked list containing attribute identifiers desired.
- * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
- *
+ *
* OUTPUT :
* int return value
- * 0
+ * 0
* The request completed successfully. This does not
* mean the requested services were found
* -1
* The request completed unsuccessfully due to a timeout
- *
+ *
* sdp_list_t *rsp_list
* This variable is set on a successful return to point to
* service(s) found. Each element of this list is of type
@@ -434,12 +434,12 @@
void sdp_record_free(sdp_record_t *rec);
/*
- * Register a service record.
- *
- * Note: It is the responsbility of the Service Provider to create the
+ * Register a service record.
+ *
+ * Note: It is the responsbility of the Service Provider to create the
* record first and set its attributes using setXXX() methods.
- *
- * The service provider must then call sdp_record_register() to make
+ *
+ * The service provider must then call sdp_record_register() to make
* the service record visible to SDP clients. This function returns 0
* on success or -1 on failure (and sets errno).
*/
@@ -473,9 +473,10 @@
uuid_t *sdp_uuid128_create(uuid_t *uuid, const void *data);
int sdp_uuid16_cmp(const void *p1, const void *p2);
int sdp_uuid128_cmp(const void *p1, const void *p2);
-uuid_t *sdp_uuid_to_uuid128(uuid_t *uuid);
-void sdp_uuid16_to_uuid128(uuid_t *uuid128, uuid_t *uuid16);
-void sdp_uuid32_to_uuid128(uuid_t *uuid128, uuid_t *uuid32);
+int sdp_uuid_cmp(const void *p1, const void *p2);
+uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid);
+void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16);
+void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32);
int sdp_uuid128_to_uuid(uuid_t *uuid);
int sdp_uuid_to_proto(uuid_t *uuid);
int sdp_uuid_extract(const uint8_t *buffer, int bufsize, uuid_t *uuid, int *scanned);
@@ -492,14 +493,14 @@
int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n);
/*
- * In all the sdp_get_XXX(handle, XXX *xxx) functions below,
+ * In all the sdp_get_XXX(handle, XXX *xxx) functions below,
* the XXX * is set to point to the value, should it exist
* and 0 is returned. If the value does not exist, -1 is
* returned and errno set to ENODATA.
*
* In all the methods below, the memory management rules are
* simple. Don't free anything! The pointer returned, in the
- * case of constructed types, is a pointer to the contents
+ * case of constructed types, is a pointer to the contents
* of the sdp_record_t.
*/
@@ -515,7 +516,7 @@
/*
* Extract the list of browse groups to which the service belongs.
- * When set, seqp contains elements of GroupID (uint16_t)
+ * When set, seqp contains elements of GroupID (uint16_t)
*/
static inline int sdp_get_browse_groups(const sdp_record_t *rec, sdp_list_t **seqp)
{
@@ -523,9 +524,9 @@
}
/*
- * Extract language attribute meta-data of the service record.
+ * Extract language attribute meta-data of the service record.
* For each language in the service record, LangSeq has a struct of type
- * sdp_lang_attr_t.
+ * sdp_lang_attr_t.
*/
int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq);
@@ -539,8 +540,8 @@
int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDesc);
/*
- * Extract SDP server version numbers
- *
+ * Extract SDP server version numbers
+ *
* Note: that this is an attribute of the SDP server only and
* contains a list of uint16_t each of which represent the
* major and minor SDP version numbers supported by this server
@@ -584,6 +585,20 @@
return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len);
}
+/*
+ * Set the supported features
+ * sf should be a list of list with each feature data
+ * Returns 0 on success -1 on fail
+ */
+int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf);
+
+/*
+ * Get the supported features
+ * seqp is set to a list of list with each feature data
+ * Returns 0 on success, if an error occurred -1 is returned and errno is set
+ */
+int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp);
+
sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int bufsize, int *scanned);
sdp_record_t *sdp_copy_record(sdp_record_t *rec);
diff --git a/lib/hci.c b/lib/hci.c
index 6d25a8b..1c455c5 100644
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -41,9 +41,9 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "bluetooth.h"
+#include "hci.h"
+#include "hci_lib.h"
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -54,7 +54,7 @@
unsigned int val;
} hci_map;
-static char *hci_bit2str(hci_map *m, unsigned int val)
+static char *hci_bit2str(hci_map *m, unsigned int val)
{
char *str = malloc(120);
char *ptr = str;
@@ -95,7 +95,7 @@
return set;
}
-static char *hci_uint2str(hci_map *m, unsigned int val)
+static char *hci_uint2str(hci_map *m, unsigned int val)
{
char *str = malloc(50);
char *ptr = str;
@@ -138,9 +138,9 @@
return set;
}
-char *hci_dtypetostr(int type)
+char *hci_bustostr(int bus)
{
- switch (type) {
+ switch (bus) {
case HCI_VIRTUAL:
return "VIRTUAL";
case HCI_USB:
@@ -160,6 +160,23 @@
}
}
+char *hci_dtypetostr(int type)
+{
+ return hci_bustostr(type & 0x0f);
+}
+
+char *hci_typetostr(int type)
+{
+ switch (type) {
+ case HCI_BREDR:
+ return "BR/EDR";
+ case HCI_80211:
+ return "802.11";
+ default:
+ return "UNKNOWN";
+ }
+}
+
/* HCI dev flags mapping */
static hci_map dev_flags_map[] = {
{ "UP", HCI_UP },
@@ -192,7 +209,7 @@
if (hci_test_bit(m->val, &flags))
ptr += sprintf(ptr, "%s ", m->str);
m++;
- }
+ }
return str;
}
@@ -473,7 +490,7 @@
{ "Write Simple Pairing Mode", 142 },
{ "Read Local OOB Data", 143 },
- { "Read Inquiry Transmit Power Level", 144 },
+ { "Read Inquiry Response Transmit Power Level", 144 },
{ "Write Inquiry Transmit Power Level", 145 },
{ "Read Default Erroneous Data Reporting", 146 },
{ "Write Default Erroneous Data Reporting", 147 },
@@ -494,12 +511,84 @@
{ "Reserved", 160 },
{ "Reserved", 161 },
{ "Send Keypress Notification", 162 },
- { "IO Capabilities Response Negative Reply", 163 },
- { "Reserved", 164 },
+ { "IO Capability Request Negative Reply", 163 },
+ { "Read Encryption Key Size", 164 },
{ "Reserved", 165 },
{ "Reserved", 166 },
{ "Reserved", 167 },
+ { "Create Physical Link", 168 },
+ { "Accept Physical Link", 169 },
+ { "Disconnect Physical Link", 170 },
+ { "Create Logical Link", 171 },
+ { "Accept Logical Link", 172 },
+ { "Disconnect Logical Link", 173 },
+ { "Logical Link Cancel", 174 },
+ { "Flow Specification Modify", 175 },
+
+ { "Read Logical Link Accept Timeout", 176 },
+ { "Write Logical Link Accept Timeout", 177 },
+ { "Set Event Mask Page 2", 178 },
+ { "Read Location Data", 179 },
+ { "Write Location Data", 180 },
+ { "Read Local AMP Info", 181 },
+ { "Read Local AMP_ASSOC", 182 },
+ { "Write Remote AMP_ASSOC", 183 },
+
+ { "Read Flow Control Mode", 184 },
+ { "Write Flow Control Mode", 185 },
+ { "Read Data Block Size", 186 },
+ { "Reserved", 187 },
+ { "Reserved", 188 },
+ { "Enable AMP Receiver Reports", 189 },
+ { "AMP Test End", 190 },
+ { "AMP Test Command", 191 },
+
+ { "Read Enhanced Transmit Power Level", 192 },
+ { "Reserved", 193 },
+ { "Read Best Effort Flush Timeout", 194 },
+ { "Write Best Effort Flush Timeout", 195 },
+ { "Short Range Mode", 196 },
+ { "Read LE Host Support", 197 },
+ { "Write LE Host Support", 198 },
+ { "Reserved", 199 },
+
+ { "LE Set Event Mask", 200 },
+ { "LE Read Buffer Size", 201 },
+ { "LE Read Local Supported Features", 202 },
+ { "Reserved", 203 },
+ { "LE Set Random Address", 204 },
+ { "LE Set Advertising Parameters", 205 },
+ { "LE Read Advertising Channel TX Power", 206 },
+ { "LE Set Advertising Data", 207 },
+
+ { "LE Set Scan Response Data", 208 },
+ { "LE Set Advertise Enable", 209 },
+ { "LE Set Scan Parameters", 210 },
+ { "LE Set Scan Enable", 211 },
+ { "LE Create Connection", 212 },
+ { "LE Create Connection Cancel", 213 },
+ { "LE Read White List Size", 214 },
+ { "LE Clear White List", 215 },
+
+ { "LE Add Device To White List", 216 },
+ { "LE Remove Device From White List", 217 },
+ { "LE Connection Update", 218 },
+ { "LE Set Host Channel Classification", 219 },
+ { "LE Read Channel Map", 220 },
+ { "LE Read Remote Used Features", 221 },
+ { "LE Encrypt", 222 },
+ { "LE Rand", 223 },
+
+ { "LE Start Encryption", 224 },
+ { "LE Long Term Key Request Reply", 225 },
+ { "LE Long Term Key Request Negative Reply", 226 },
+ { "LE Read Supported States", 227 },
+ { "LE Receiver Test", 228 },
+ { "LE Transmitter Test", 229 },
+ { "LE Test End", 230 },
+ { "Reserved", 231 },
+
{ NULL }
};
@@ -558,6 +647,7 @@
{ "2.0", 0x03 },
{ "2.1", 0x04 },
{ "3.0", 0x05 },
+ { "4.0", 0x06 },
{ NULL }
};
@@ -630,8 +720,8 @@
{ "<no. 34>", 0x04 }, /* Bit 2 */
{ "<AFH cap. slave>", LMP_AFH_CAP_SLV }, /* Bit 3 */
{ "<AFH class. slave>", LMP_AFH_CLS_SLV }, /* Bit 4 */
- { "<no. 37>", 0x20 }, /* Bit 5 */
- { "<no. 38>", 0x40 }, /* Bit 6 */
+ { "<BR/EDR not supp.>", LMP_NO_BREDR }, /* Bit 5 */
+ { "<LE support>", LMP_LE }, /* Bit 6 */
{ "<3-slot EDR ACL>", LMP_EDR_3SLOT }, /* Bit 7 */
{ NULL }
},
@@ -648,7 +738,7 @@
},
{ /* Byte 6 */
{ "<extended inquiry>", LMP_EXT_INQ }, /* Bit 0 */
- { "<no. 49>", 0x02 }, /* Bit 1 */
+ { "<LE and BR/EDR>", LMP_LE_BREDR }, /* Bit 1 */
{ "<no. 50>", 0x04 }, /* Bit 2 */
{ "<simple pairing>", LMP_SIMPLE_PAIR }, /* Bit 3 */
{ "<encapsulated PDU>", LMP_ENCAPS_PDU }, /* Bit 4 */
@@ -660,7 +750,7 @@
{ /* Byte 7 */
{ "<LSTO>", LMP_LSTO }, /* Bit 1 */
{ "<inquiry TX power>", LMP_INQ_TX_PWR }, /* Bit 1 */
- { "<no. 58>", 0x04 }, /* Bit 2 */
+ { "<EPC>", LMP_EPC }, /* Bit 2 */
{ "<no. 59>", 0x08 }, /* Bit 3 */
{ "<no. 60>", 0x10 }, /* Bit 4 */
{ "<no. 61>", 0x20 }, /* Bit 5 */
@@ -869,7 +959,7 @@
errno = ENODEV;
return -1;
}
- }
+ }
dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
if (dd < 0)
@@ -919,7 +1009,7 @@
return ret;
}
-/* Open HCI device.
+/* Open HCI device.
* Returns device descriptor (dd). */
int hci_open_dev(int dev_id)
{
@@ -1003,6 +1093,7 @@
hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
hci_filter_set_event(EVT_CMD_STATUS, &nf);
hci_filter_set_event(EVT_CMD_COMPLETE, &nf);
+ hci_filter_set_event(EVT_LE_META_EVENT, &nf);
hci_filter_set_event(r->event, &nf);
hci_filter_set_opcode(opcode, &nf);
if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0)
@@ -1016,6 +1107,7 @@
evt_cmd_complete *cc;
evt_cmd_status *cs;
evt_remote_name_req_complete *rn;
+ evt_le_meta_event *me;
remote_name_req_cp *cp;
int len;
@@ -1096,6 +1188,17 @@
memcpy(r->rparam, ptr, r->rlen);
goto done;
+ case EVT_LE_META_EVENT:
+ me = (void *) ptr;
+
+ if (me->subevent != r->event)
+ continue;
+
+ len -= 1;
+ r->rlen = MIN(len, r->rlen);
+ memcpy(r->rparam, me->data, r->rlen);
+ goto done;
+
default:
if (hdr->evt != r->event)
break;
@@ -2173,16 +2276,16 @@
return 0;
}
-int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to)
+int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to)
{
- read_inquiry_transmit_power_level_rp rp;
+ read_inq_response_tx_power_level_rp rp;
struct hci_request rq;
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_HOST_CTL;
- rq.ocf = OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL;
+ rq.ocf = OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL;
rq.rparam = &rp;
- rq.rlen = READ_INQUIRY_TRANSMIT_POWER_LEVEL_RP_SIZE;
+ rq.rlen = READ_INQ_RESPONSE_TX_POWER_LEVEL_RP_SIZE;
if (hci_send_req(dd, &rq, to) < 0)
return -1;
@@ -2196,6 +2299,11 @@
return 0;
}
+int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to)
+{
+ return hci_read_inq_response_tx_power_level(dd, level, to);
+}
+
int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to)
{
write_inquiry_transmit_power_level_cp cp;
@@ -2496,3 +2604,143 @@
*accuracy = rp.accuracy;
return 0;
}
+
+int hci_le_set_scan_enable(int dd, uint8_t enable, uint8_t filter_dup)
+{
+ struct hci_request rq;
+ le_set_scan_enable_cp scan_cp;
+ uint8_t status;
+
+ memset(&scan_cp, 0, sizeof(scan_cp));
+ scan_cp.enable = enable;
+ scan_cp.filter_dup = filter_dup;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LE_CTL;
+ rq.ocf = OCF_LE_SET_SCAN_ENABLE;
+ rq.cparam = &scan_cp;
+ rq.clen = LE_SET_SCAN_ENABLE_CP_SIZE;
+ rq.rparam = &status;
+ rq.rlen = 1;
+
+ if (hci_send_req(dd, &rq, 100) < 0)
+ return -1;
+
+ if (status) {
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+int hci_le_set_scan_parameters(int dd, uint8_t type,
+ uint16_t interval, uint16_t window,
+ uint8_t own_type, uint8_t filter)
+{
+ struct hci_request rq;
+ le_set_scan_parameters_cp param_cp;
+ uint8_t status;
+
+ memset(¶m_cp, 0, sizeof(param_cp));
+ param_cp.type = type;
+ param_cp.interval = interval;
+ param_cp.window = window;
+ param_cp.own_bdaddr_type = own_type;
+ param_cp.filter = filter;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LE_CTL;
+ rq.ocf = OCF_LE_SET_SCAN_PARAMETERS;
+ rq.cparam = ¶m_cp;
+ rq.clen = LE_SET_SCAN_PARAMETERS_CP_SIZE;
+ rq.rparam = &status;
+ rq.rlen = 1;
+
+ if (hci_send_req(dd, &rq, 100) < 0)
+ return -1;
+
+ if (status) {
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+int hci_le_set_advertise_enable(int dd, uint8_t enable)
+{
+ struct hci_request rq;
+ le_set_advertise_enable_cp adv_cp;
+ uint8_t status;
+
+ memset(&adv_cp, 0, sizeof(adv_cp));
+ adv_cp.enable = enable;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LE_CTL;
+ rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE;
+ rq.cparam = &adv_cp;
+ rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;
+ rq.rparam = &status;
+ rq.rlen = 1;
+
+ if (hci_send_req(dd, &rq, 100) < 0)
+ return -1;
+
+ if (status) {
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
+ uint8_t initiator_filter, uint8_t peer_bdaddr_type,
+ bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
+ uint16_t min_interval, uint16_t max_interval,
+ uint16_t latency, uint16_t supervision_timeout,
+ uint16_t min_ce_length, uint16_t max_ce_length,
+ uint16_t *handle, int to)
+{
+ struct hci_request rq;
+ le_create_connection_cp create_conn_cp;
+ evt_le_connection_complete conn_complete_rp;
+
+ memset(&create_conn_cp, 0, sizeof(create_conn_cp));
+ create_conn_cp.interval = interval;
+ create_conn_cp.window = window;
+ create_conn_cp.initiator_filter = initiator_filter;
+ create_conn_cp.peer_bdaddr_type = peer_bdaddr_type;
+ create_conn_cp.peer_bdaddr = peer_bdaddr;
+ create_conn_cp.own_bdaddr_type = own_bdaddr_type;
+ create_conn_cp.min_interval = min_interval;
+ create_conn_cp.max_interval = max_interval;
+ create_conn_cp.latency = latency;
+ create_conn_cp.supervision_timeout = supervision_timeout;
+ create_conn_cp.min_ce_length = min_ce_length;
+ create_conn_cp.max_ce_length = max_ce_length;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LE_CTL;
+ rq.ocf = OCF_LE_CREATE_CONN;
+ rq.event = EVT_LE_CONN_COMPLETE;
+ rq.cparam = &create_conn_cp;
+ rq.clen = LE_CREATE_CONN_CP_SIZE;
+ rq.rparam = &conn_complete_rp;
+ rq.rlen = EVT_CONN_COMPLETE_SIZE;
+
+ if (hci_send_req(dd, &rq, to) < 0)
+ return -1;
+
+ if (conn_complete_rp.status) {
+ errno = EIO;
+ return -1;
+ }
+
+ if (handle)
+ *handle = conn_complete_rp.handle;
+
+ return 0;
+}
diff --git a/lib/sdp.c b/lib/sdp.c
index bf34c3c..17745ac 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -40,16 +40,15 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
#include <netinet/in.h>
+#include "bluetooth.h"
+#include "hci.h"
+#include "hci_lib.h"
+#include "l2cap.h"
+#include "sdp.h"
+#include "sdp_lib.h"
+
#define SDPINF(fmt, arg...) syslog(LOG_INFO, fmt "\n", ## arg)
#define SDPERR(fmt, arg...) syslog(LOG_ERR, "%s: " fmt "\n", __func__ , ## arg)
@@ -202,9 +201,9 @@
{ VIDEO_SOURCE_SVCLASS_ID, "Video Source" },
{ VIDEO_SINK_SVCLASS_ID, "Video Sink" },
{ VIDEO_DISTRIBUTION_SVCLASS_ID, "Video Distribution" },
- { MDP_SVCLASS_ID, "MDP" },
- { MDP_SOURCE_SVCLASS_ID, "MDP Source" },
- { MDP_SINK_SVCLASS_ID, "MDP Sink" },
+ { HDP_SVCLASS_ID, "HDP" },
+ { HDP_SOURCE_SVCLASS_ID, "HDP Source" },
+ { HDP_SINK_SVCLASS_ID, "HDP Sink" },
{ APPLE_AGENT_SVCLASS_ID, "Apple Agent" },
{ 0 }
};
@@ -638,14 +637,14 @@
void sdp_set_seq_len(uint8_t *ptr, uint32_t length)
{
- uint8_t dtd = *(uint8_t *) ptr++;
+ uint8_t dtd = *ptr++;
switch (dtd) {
case SDP_SEQ8:
case SDP_ALT8:
case SDP_TEXT_STR8:
case SDP_URL_STR8:
- *(uint8_t *)ptr = (uint8_t) length;
+ *ptr = (uint8_t) length;
break;
case SDP_SEQ16:
case SDP_ALT16:
@@ -1079,6 +1078,8 @@
}
d = malloc(sizeof(sdp_data_t));
+ if (!d)
+ return NULL;
SDPDBG("Extracting integer\n");
memset(d, 0, sizeof(sdp_data_t));
@@ -1153,13 +1154,16 @@
{
sdp_data_t *d = malloc(sizeof(sdp_data_t));
+ if (!d)
+ return NULL;
+
SDPDBG("Extracting UUID");
memset(d, 0, sizeof(sdp_data_t));
if (sdp_uuid_extract(p, bufsize, &d->val.uuid, len) < 0) {
free(d);
return NULL;
}
- d->dtd = *(uint8_t *) p;
+ d->dtd = *p;
if (rec)
sdp_pattern_add_uuid(rec, &d->val.uuid);
return d;
@@ -1180,6 +1184,8 @@
}
d = malloc(sizeof(sdp_data_t));
+ if (!d)
+ return NULL;
memset(d, 0, sizeof(sdp_data_t));
d->dtd = *(uint8_t *) p;
@@ -1215,7 +1221,7 @@
default:
SDPERR("Sizeof text string > UINT16_MAX\n");
free(d);
- return 0;
+ return NULL;
}
if (bufsize < n) {
@@ -1303,6 +1309,9 @@
sdp_data_t *curr, *prev;
sdp_data_t *d = malloc(sizeof(sdp_data_t));
+ if (!d)
+ return NULL;
+
SDPDBG("Extracting SEQ");
memset(d, 0, sizeof(sdp_data_t));
*len = sdp_extract_seqtype(p, bufsize, &d->dtd, &seqlen);
@@ -1575,7 +1584,7 @@
value = sdp_data_value(tmp, NULL);
datatmp = sdp_data_alloc_with_length(tmp->dtd, value,
- tmp->unitSize);
+ tmp->unitSize);
if (cur)
cur->next = datatmp;
@@ -1601,7 +1610,7 @@
sdp_attr_add_new(rec, data->attrId, data->dtd, val);
else
sdp_attr_add_new_with_length(rec, data->attrId,
- data->dtd, val, len);
+ data->dtd, val, len);
}
sdp_record_t *sdp_copy_record(sdp_record_t *rec)
@@ -1703,7 +1712,7 @@
sdpTemplate.attrId = attrId;
p = sdp_list_find(rec->attrlist, &sdpTemplate, sdp_attrid_comp_func);
if (p)
- return (sdp_data_t *)p->data;
+ return p->data;
}
return NULL;
}
@@ -1744,8 +1753,8 @@
uint8_t *rspbuf, uint32_t reqsize, uint32_t *rspsize)
{
int n;
- sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)reqbuf;
- sdp_pdu_hdr_t *rsphdr = (sdp_pdu_hdr_t *)rspbuf;
+ sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *) reqbuf;
+ sdp_pdu_hdr_t *rsphdr = (sdp_pdu_hdr_t *) rspbuf;
SDPDBG("");
if (0 > sdp_send_req(session, reqbuf, reqsize)) {
@@ -1772,7 +1781,7 @@
sdp_list_t *q, *n = malloc(sizeof(sdp_list_t));
if (!n)
- return 0;
+ return NULL;
n->data = d;
n->next = 0;
@@ -1810,7 +1819,7 @@
n = malloc(sizeof(sdp_list_t));
if (!n)
- return 0;
+ return NULL;
n->data = d;
for (q = 0, p = list; p; q = p, p = p->next)
if (f(p->data, d) >= 0)
@@ -1867,7 +1876,7 @@
for (; list; list = list->next) {
sdp_list_t *p;
for (p = list->data; p; p = p->next) {
- sdp_data_t *seq = (sdp_data_t *) p->data;
+ sdp_data_t *seq = p->data;
int port = __find_port(seq, proto);
if (port)
return port;
@@ -1881,7 +1890,7 @@
for (; list; list = list->next) {
sdp_list_t *p;
for (p = list->data; p; p = p->next) {
- sdp_data_t *seq = (sdp_data_t *) p->data;
+ sdp_data_t *seq = p->data;
if (SDP_IS_UUID(seq->dtd) &&
sdp_uuid_to_proto(&seq->val.uuid) == proto)
return seq->next;
@@ -1946,10 +1955,15 @@
sdp_data_t *d;
for (d = sdpdata->val.dataseq; d; d = d->next) {
uuid_t *u;
- if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128)
+ if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128) {
+ errno = EINVAL;
goto fail;
+ }
u = malloc(sizeof(uuid_t));
+ if (!u)
+ goto fail;
+
memset(u, 0, sizeof(uuid_t));
*u = d->val.uuid;
*seqp = sdp_list_append(*seqp, u);
@@ -1958,7 +1972,7 @@
}
fail:
sdp_list_free(*seqp, free);
- errno = EINVAL;
+ *seqp = NULL;
return -1;
}
@@ -1974,10 +1988,18 @@
len = sdp_list_len(seq);
if (!seq || len == 0)
return -1;
- dtds = (void **)malloc(len * sizeof(void *));
- values = (void **)malloc(len * sizeof(void *));
+ dtds = malloc(len * sizeof(void *));
+ if (!dtds)
+ return -1;
+
+ values = malloc(len * sizeof(void *));
+ if (!values) {
+ free(dtds);
+ return -1;
+ }
+
for (p = seq, i = 0; i < len; i++, p = p->next) {
- uuid_t *uuid = (uuid_t *)p->data;
+ uuid_t *uuid = p->data;
if (uuid)
switch (uuid->type) {
case SDP_UUID16:
@@ -2027,8 +2049,13 @@
sdp_data_t *pCode = curr_data;
sdp_data_t *pEncoding = pCode->next;
sdp_data_t *pOffset = pEncoding->next;
- if (pCode && pEncoding && pOffset) {
+ if (pEncoding && pOffset) {
lang = malloc(sizeof(sdp_lang_attr_t));
+ if (!lang) {
+ sdp_list_free(*langSeq, free);
+ *langSeq = NULL;
+ return -1;
+ }
lang->code_ISO639 = pCode->val.uint16;
lang->encoding = pEncoding->val.uint16;
lang->base_offset = pOffset->val.uint16;
@@ -2070,6 +2097,11 @@
if (uuid != NULL) {
profDesc = malloc(sizeof(sdp_profile_desc_t));
+ if (!profDesc) {
+ sdp_list_free(*profDescSeq, free);
+ *profDescSeq = NULL;
+ return -1;
+ }
profDesc->uuid = *uuid;
profDesc->version = version;
#ifdef SDP_DEBUG
@@ -2212,14 +2244,14 @@
const char *desc)
{
if (name)
- sdp_attr_add_new(rec, SDP_ATTR_SVCNAME_PRIMARY, SDP_TEXT_STR8,
- (void *)name);
+ sdp_attr_add_new(rec, SDP_ATTR_SVCNAME_PRIMARY,
+ SDP_TEXT_STR8, name);
if (prov)
- sdp_attr_add_new(rec, SDP_ATTR_PROVNAME_PRIMARY, SDP_TEXT_STR8,
- (void *)prov);
+ sdp_attr_add_new(rec, SDP_ATTR_PROVNAME_PRIMARY,
+ SDP_TEXT_STR8, prov);
if (desc)
- sdp_attr_add_new(rec, SDP_ATTR_SVCDESC_PRIMARY, SDP_TEXT_STR8,
- (void *)desc);
+ sdp_attr_add_new(rec, SDP_ATTR_SVCDESC_PRIMARY,
+ SDP_TEXT_STR8, desc);
}
static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto)
@@ -2231,15 +2263,23 @@
sdp_list_t *p;
seqlen = sdp_list_len(proto);
- seqDTDs = (void **)malloc(seqlen * sizeof(void *));
- seqs = (void **)malloc(seqlen * sizeof(void *));
+ seqDTDs = malloc(seqlen * sizeof(void *));
+ if (!seqDTDs)
+ return NULL;
+
+ seqs = malloc(seqlen * sizeof(void *));
+ if (!seqs) {
+ free(seqDTDs);
+ return NULL;
+ }
+
for (i = 0, p = proto; p; p = p->next, i++) {
- sdp_list_t *elt = (sdp_list_t *)p->data;
+ sdp_list_t *elt = p->data;
sdp_data_t *s;
uuid_t *uuid = NULL;
unsigned int pslen = 0;
for (; elt && pslen < ARRAY_SIZE(dtds); elt = elt->next, pslen++) {
- sdp_data_t *d = (sdp_data_t *)elt->data;
+ sdp_data_t *d = elt->data;
dtds[pslen] = &d->dtd;
switch (d->dtd) {
case SDP_UUID16:
@@ -2304,8 +2344,7 @@
sdp_data_t *protos = NULL;
for (p = ap; p; p = p->next) {
- sdp_data_t *seq = access_proto_to_dataseq(rec,
- (sdp_list_t *) p->data);
+ sdp_data_t *seq = access_proto_to_dataseq(rec, p->data);
protos = sdp_seq_append(protos, seq);
}
@@ -2320,8 +2359,7 @@
sdp_data_t *protos = NULL;
for (p = ap; p; p = p->next) {
- sdp_data_t *seq = access_proto_to_dataseq(rec,
- (sdp_list_t *) p->data);
+ sdp_data_t *seq = access_proto_to_dataseq(rec, p->data);
protos = sdp_seq_append(protos, seq);
}
@@ -2351,12 +2389,21 @@
{
uint8_t uint16 = SDP_UINT16;
int status = 0, i = 0, seqlen = sdp_list_len(seq);
- void **dtds = (void **)malloc(3 * seqlen * sizeof(void *));
- void **values = (void **)malloc(3 * seqlen * sizeof(void *));
+ void **dtds, **values;
const sdp_list_t *p;
+ dtds = malloc(3 * seqlen * sizeof(void *));
+ if (!dtds)
+ return -1;
+
+ values = malloc(3 * seqlen * sizeof(void *));
+ if (!values) {
+ free(dtds);
+ return -1;
+ }
+
for (p = seq; p; p = p->next) {
- sdp_lang_attr_t *lang = (sdp_lang_attr_t *)p->data;
+ sdp_lang_attr_t *lang = p->data;
if (!lang) {
status = -1;
break;
@@ -2456,14 +2503,23 @@
uint8_t uuid128 = SDP_UUID128;
uint8_t uint16 = SDP_UINT16;
int i = 0, seqlen = sdp_list_len(profiles);
- void **seqDTDs = (void **)malloc(seqlen * sizeof(void *));
- void **seqs = (void **)malloc(seqlen * sizeof(void *));
+ void **seqDTDs, **seqs;
const sdp_list_t *p;
+ seqDTDs = malloc(seqlen * sizeof(void *));
+ if (!seqDTDs)
+ return -1;
+
+ seqs = malloc(seqlen * sizeof(void *));
+ if (!seqs) {
+ free(seqDTDs);
+ return -1;
+ }
+
for (p = profiles; p; p = p->next) {
sdp_data_t *seq;
void *dtds[2], *values[2];
- sdp_profile_desc_t *profile = (sdp_profile_desc_t *)p->data;
+ sdp_profile_desc_t *profile = p->data;
if (!profile) {
status = -1;
break;
@@ -2556,10 +2612,28 @@
* UUID comparison function
* returns 0 if uuidValue1 == uuidValue2 else -1
*/
+int sdp_uuid_cmp(const void *p1, const void *p2)
+{
+ uuid_t *u1 = sdp_uuid_to_uuid128(p1);
+ uuid_t *u2 = sdp_uuid_to_uuid128(p2);
+ int ret;
+
+ ret = sdp_uuid128_cmp(u1, u2);
+
+ bt_free(u1);
+ bt_free(u2);
+
+ return ret;
+}
+
+/*
+ * UUID comparison function
+ * returns 0 if uuidValue1 == uuidValue2 else -1
+ */
int sdp_uuid16_cmp(const void *p1, const void *p2)
{
- const uuid_t *u1 = (const uuid_t *)p1;
- const uuid_t *u2 = (const uuid_t *)p2;
+ const uuid_t *u1 = p1;
+ const uuid_t *u2 = p2;
return memcmp(&u1->value.uuid16, &u2->value.uuid16, sizeof(uint16_t));
}
@@ -2569,8 +2643,8 @@
*/
int sdp_uuid128_cmp(const void *p1, const void *p2)
{
- const uuid_t *u1 = (const uuid_t *)p1;
- const uuid_t *u2 = (const uuid_t *)p2;
+ const uuid_t *u1 = p1;
+ const uuid_t *u2 = p2;
return memcmp(&u1->value.uuid128, &u2->value.uuid128, sizeof(uint128_t));
}
@@ -2579,7 +2653,7 @@
* yet to be implemented. Note that the input is in NBO in
* both 32 and 128 bit UUIDs and conversion is needed
*/
-void sdp_uuid16_to_uuid128(uuid_t *uuid128, uuid_t *uuid16)
+void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16)
{
/*
* We have a 16 bit value, which needs to be added to
@@ -2601,7 +2675,7 @@
memcpy(&uuid128->value.uuid128.data[2], &data1, 2);
}
-void sdp_uuid32_to_uuid128(uuid_t *uuid128, uuid_t *uuid32)
+void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32)
{
/*
* We have a 32 bit value, which needs to be added to
@@ -2623,9 +2697,13 @@
memcpy(&uuid128->value.uuid128.data[0], &data0, 4);
}
-uuid_t *sdp_uuid_to_uuid128(uuid_t *uuid)
+uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid)
{
uuid_t *uuid128 = bt_malloc(sizeof(uuid_t));
+
+ if (!uuid128)
+ return NULL;
+
memset(uuid128, 0, sizeof(uuid_t));
switch (uuid->type) {
case SDP_UUID128:
@@ -2697,14 +2775,14 @@
void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len)
{
uint8_t *p = dst->data;
- uint8_t dtd = *(uint8_t *) p;
+ 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);
if (dst->data_size == 0 && dtd == 0) {
/* create initial sequence */
- *(uint8_t *)p = SDP_SEQ8;
+ *p = SDP_SEQ8;
p += sizeof(uint8_t);
dst->data_size += sizeof(uint8_t);
/* reserve space for sequence size */
@@ -2715,13 +2793,13 @@
memcpy(dst->data + dst->data_size, data, len);
dst->data_size += len;
- dtd = *(uint8_t *)dst->data;
+ dtd = *(uint8_t *) dst->data;
if (dst->data_size > UCHAR_MAX && dtd == SDP_SEQ8) {
short offset = sizeof(uint8_t) + sizeof(uint8_t);
memmove(dst->data + offset + 1, dst->data + offset,
dst->data_size - offset);
p = dst->data;
- *(uint8_t *) p = SDP_SEQ16;
+ *p = SDP_SEQ16;
p += sizeof(uint8_t);
dst->data_size += 1;
}
@@ -2837,11 +2915,8 @@
}
end:
- if (req)
- free(req);
-
- if (rsp)
- free(rsp);
+ free(req);
+ free(rsp);
return status;
}
@@ -2947,11 +3022,8 @@
status = -1;
}
end:
- if (reqbuf)
- free(reqbuf);
-
- if (rspbuf)
- free(rspbuf);
+ free(reqbuf);
+ free(rspbuf);
return status;
}
@@ -3055,10 +3127,8 @@
status = -1;
}
end:
- if (reqbuf)
- free(reqbuf);
- if (rspbuf)
- free(rspbuf);
+ free(reqbuf);
+ free(rspbuf);
return status;
}
@@ -3070,7 +3140,11 @@
sdp_record_t *sdp_record_alloc()
{
sdp_record_t *rec = malloc(sizeof(sdp_record_t));
- memset((void *)rec, 0, sizeof(sdp_record_t));
+
+ if (!rec)
+ return NULL;
+
+ memset(rec, 0, sizeof(sdp_record_t));
rec->handle = 0xffffffff;
return rec;
}
@@ -3080,7 +3154,7 @@
*/
void sdp_record_free(sdp_record_t *rec)
{
- sdp_list_free(rec->attrlist, (sdp_free_func_t)sdp_data_free);
+ sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free);
sdp_list_free(rec->pattern, free);
free(rec);
}
@@ -3089,9 +3163,8 @@
{
uuid_t *uuid128 = sdp_uuid_to_uuid128(uuid);
- SDPDBG("SvcRec : 0x%lx\n", (unsigned long)rec);
SDPDBG("Elements in target pattern : %d\n", sdp_list_len(rec->pattern));
- SDPDBG("Trying to add : 0x%lx\n", (unsigned long)uuid128);
+ SDPDBG("Trying to add : 0x%lx\n", (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);
@@ -3206,7 +3279,7 @@
static int gen_searchseq_pdu(uint8_t *dst, const sdp_list_t *seq)
{
- uuid_t *uuid = (uuid_t *) seq->data;
+ uuid_t *uuid = seq->data;
return gen_dataseq_pdu(dst, seq, uuid->type);
}
@@ -3237,7 +3310,7 @@
}
/*
- * This is a service search request.
+ * This is a service search request.
*
* INPUT :
*
@@ -3391,16 +3464,14 @@
} while (cstate);
end:
- if (reqbuf)
- free(reqbuf);
- if (rspbuf)
- free(rspbuf);
+ free(reqbuf);
+ free(rspbuf);
return status;
}
/*
- * This is a service attribute request.
+ * This is a service attribute request.
*
* INPUT :
*
@@ -3421,7 +3492,7 @@
*
* sdp_list_t *attrid
* Singly linked list containing attribute identifiers desired.
- * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
*
* OUTPUT :
@@ -3431,7 +3502,7 @@
* !0:
* The service record
*/
-sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
+sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
sdp_attrreq_type_t reqtype, const sdp_list_t *attrids)
{
uint32_t reqsize = 0, _reqsize;
@@ -3449,16 +3520,17 @@
if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) {
errno = EINVAL;
- return 0;
+ return NULL;
}
+ memset(&rsp_concat_buf, 0, sizeof(sdp_buf_t));
+
reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
if (!reqbuf || !rspbuf) {
errno = ENOMEM;
goto end;
}
- memset((char *) &rsp_concat_buf, 0, sizeof(sdp_buf_t));
reqhdr = (sdp_pdu_hdr_t *) reqbuf;
reqhdr->pdu_id = SDP_SVC_ATTR_REQ;
@@ -3476,7 +3548,7 @@
pdata += sizeof(uint16_t);
// get attr seq PDU form
- seqlen = gen_attridseq_pdu(pdata, attrids,
+ seqlen = gen_attridseq_pdu(pdata, attrids,
reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32);
if (seqlen == -1) {
errno = EINVAL;
@@ -3540,7 +3612,7 @@
SDPDBG("sdp_cstate_t length : %d\n", cstate_len);
/*
- * a split response: concatenate intermediate responses
+ * a split response: concatenate intermediate responses
* and the last one (which has cstate_len == 0)
*/
if (cstate_len > 0 || rsp_concat_buf.data_size != 0) {
@@ -3565,14 +3637,11 @@
}
rec = sdp_extract_pdu(pdata, pdata_len, &scanned);
}
-
+
end:
- if (reqbuf)
- free(reqbuf);
- if (rsp_concat_buf.data)
- free(rsp_concat_buf.data);
- if (rspbuf)
- free(rspbuf);
+ free(reqbuf);
+ free(rsp_concat_buf.data);
+ free(rspbuf);
return rec;
}
@@ -3658,7 +3727,7 @@
/*
* This function starts an asynchronous service search request.
- * The incomming and outgoing data are stored in the transaction structure
+ * The incomming and outgoing data are stored in the transaction structure
* buffers. When there is incomming data the sdp_process function must be
* called to get the data and handle the continuation state.
*
@@ -3695,9 +3764,8 @@
t = session->priv;
- /* check if the buffer is already allocated */
- if (t->rsp_concat_buf.data)
- free(t->rsp_concat_buf.data);
+ /* clean possible allocated buffer */
+ free(t->rsp_concat_buf.data);
memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
if (!t->reqbuf) {
@@ -3743,17 +3811,15 @@
return 0;
end:
- if (t->reqbuf) {
- free(t->reqbuf);
- t->reqbuf = NULL;
- }
+ free(t->reqbuf);
+ t->reqbuf = NULL;
return -1;
}
/*
* This function starts an asynchronous service attribute request.
- * The incomming and outgoing data are stored in the transaction structure
+ * The incomming and outgoing data are stored in the transaction structure
* buffers. When there is incomming data the sdp_process function must be
* called to get the data and handle the continuation state.
*
@@ -3778,7 +3844,7 @@
*
* sdp_list_t *attrid_list
* Singly linked list containing attribute identifiers desired.
- * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
*
* OUTPUT :
@@ -3799,9 +3865,8 @@
t = session->priv;
- /* check if the buffer is already allocated */
- if (t->rsp_concat_buf.data)
- free(t->rsp_concat_buf.data);
+ /* clean possible allocated buffer */
+ free(t->rsp_concat_buf.data);
memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
if (!t->reqbuf) {
@@ -3857,10 +3922,8 @@
return 0;
end:
- if (t->reqbuf) {
- free(t->reqbuf);
- t->reqbuf = NULL;
- }
+ free(t->reqbuf);
+ t->reqbuf = NULL;
return -1;
}
@@ -3894,7 +3957,7 @@
*
* sdp_list_t *attrid_list
* Singly linked list containing attribute identifiers desired.
- * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
*
@@ -3914,9 +3977,8 @@
t = session->priv;
- /* check if the buffer is already allocated */
- if (t->rsp_concat_buf.data)
- free(t->rsp_concat_buf.data);
+ /* clean possible allocated buffer */
+ free(t->rsp_concat_buf.data);
memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
if (!t->reqbuf) {
@@ -3976,10 +4038,8 @@
return 0;
end:
- if (t->reqbuf) {
- free(t->reqbuf);
- t->reqbuf = NULL;
- }
+ free(t->reqbuf);
+ t->reqbuf = NULL;
return -1;
}
@@ -4112,7 +4172,7 @@
pdata += sizeof(uint16_t); /* point to csrc */
/* the first csrc contains the sum of partial csrc responses */
- *pcsrc += bt_get_unaligned((uint16_t *) pdata);
+ *pcsrc += bt_get_unaligned((uint16_t *) pdata);
pdata += sizeof(uint16_t); /* point to the first handle */
rsp_count = csrc * 4;
@@ -4123,8 +4183,8 @@
case SDP_SVC_SEARCH_ATTR_RSP:
rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
SDPDBG("Attrlist byte count : %d\n", rsp_count);
-
- /*
+
+ /*
* Number of bytes in the AttributeLists parameter(without
* continuation state) + AttributeListsByteCount field size.
*/
@@ -4150,7 +4210,7 @@
SDPDBG("Cstate length : %d\n", pcstate->length);
- /*
+ /*
* Check out of bound. Continuation state must have at least
* 1 byte: ZERO to indicate that it is not a partial response.
*/
@@ -4184,7 +4244,7 @@
// set the request header's param length
reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
-
+
if (sdp_send_req(session, t->reqbuf, reqsize) < 0) {
SDPERR("Error sendind data:%s(%d)", strerror(errno), errno);
status = 0xffff;
@@ -4204,8 +4264,7 @@
t->cb(pdu_id, status, pdata, size, t->udata);
}
- if (rspbuf)
- free(rspbuf);
+ free(rspbuf);
return err;
}
@@ -4235,7 +4294,7 @@
*
* sdp_list_t *attrids
* Singly linked list containing attribute identifiers desired.
- * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
*
* OUTPUT :
@@ -4271,6 +4330,9 @@
errno = EINVAL;
return -1;
}
+
+ memset(&rsp_concat_buf, 0, sizeof(sdp_buf_t));
+
reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
if (!reqbuf || !rspbuf) {
@@ -4279,7 +4341,6 @@
goto end;
}
- memset((char *)&rsp_concat_buf, 0, sizeof(sdp_buf_t));
reqhdr = (sdp_pdu_hdr_t *) reqbuf;
reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;
@@ -4437,12 +4498,9 @@
}
}
end:
- if (rsp_concat_buf.data)
- free(rsp_concat_buf.data);
- if (reqbuf)
- free(reqbuf);
- if (rspbuf)
- free(rspbuf);
+ free(rsp_concat_buf.data);
+ free(reqbuf);
+ free(rspbuf);
return status;
}
@@ -4473,11 +4531,9 @@
t = session->priv;
if (t) {
- if (t->reqbuf)
- free(t->reqbuf);
+ free(t->reqbuf);
- if (t->rsp_concat_buf.data)
- free(t->rsp_concat_buf.data);
+ free(t->rsp_concat_buf.data);
free(t);
}
@@ -4502,7 +4558,7 @@
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path, SDP_UNIX_PATH);
- return connect(session->sock, (struct sockaddr *)&sa, sizeof(sa));
+ return connect(session->sock, (struct sockaddr *) &sa, sizeof(sa));
}
static int sdp_connect_l2cap(const bdaddr_t *src,
@@ -4584,8 +4640,7 @@
err = errno;
if (session->sock >= 0)
close(session->sock);
- if (session->priv)
- free(session->priv);
+ free(session->priv);
free(session);
errno = err;
@@ -4601,3 +4656,162 @@
{
return session->tid++;
}
+
+/*
+ * Set the supported features
+ */
+int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf)
+{
+ const sdp_list_t *p, *r;
+ sdp_data_t *feat, *seq_feat;
+ int seqlen, i;
+ void **seqDTDs, **seqVals;
+
+ seqlen = sdp_list_len(sf);
+ seqDTDs = malloc(seqlen * sizeof(void *));
+ if (!seqDTDs)
+ return -1;
+ seqVals = malloc(seqlen * sizeof(void *));
+ if (!seqVals) {
+ free(seqDTDs);
+ return -1;
+ }
+
+ for (p = sf, i = 0; p; p = p->next, i++) {
+ int plen, j;
+ void **dtds, **vals;
+ int *lengths;
+
+ plen = sdp_list_len(p->data);
+ dtds = malloc(plen * sizeof(void *));
+ if (!dtds)
+ goto fail;
+ vals = malloc(plen * sizeof(void *));
+ if (!vals) {
+ free(dtds);
+ goto fail;
+ }
+ lengths = malloc(plen * sizeof(int *));
+ if (!lengths) {
+ free(dtds);
+ free(vals);
+ goto fail;
+ }
+ for (r = p->data, j = 0; r; r = r->next, j++) {
+ sdp_data_t *data = (sdp_data_t*)r->data;
+ dtds[j] = &data->dtd;
+ switch (data->dtd) {
+ case SDP_URL_STR8:
+ case SDP_URL_STR16:
+ case SDP_TEXT_STR8:
+ case SDP_TEXT_STR16:
+ vals[j] = data->val.str;
+ lengths[j] = data->unitSize - sizeof(uint8_t);
+ break;
+ case SDP_ALT8:
+ case SDP_ALT16:
+ case SDP_ALT32:
+ case SDP_SEQ8:
+ case SDP_SEQ16:
+ case SDP_SEQ32:
+ vals[j] = data->val.dataseq;
+ lengths[j] = 0;
+ break;
+ default:
+ vals[j] = &data->val;
+ lengths[j] = 0;
+ break;
+ }
+ }
+ feat = sdp_seq_alloc_with_length(dtds, vals, lengths, plen);
+ free(dtds);
+ free(vals);
+ free(lengths);
+ if (!feat)
+ goto fail;
+ seqDTDs[i] = &feat->dtd;
+ seqVals[i] = feat;
+ }
+ seq_feat = sdp_seq_alloc(seqDTDs, seqVals, seqlen);
+ if (!seq_feat)
+ goto fail;
+ sdp_attr_replace(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST, seq_feat);
+
+ free(seqVals);
+ free(seqDTDs);
+ return 0;
+
+fail:
+ free(seqVals);
+ free(seqDTDs);
+ return -1;
+}
+
+/*
+ * Get the supported features
+ * If an error occurred -1 is returned and errno is set
+ */
+int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp)
+{
+ sdp_data_t *sdpdata, *d;
+ sdp_list_t *tseq;
+ tseq = NULL;
+
+ sdpdata = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
+
+ if (!sdpdata || sdpdata->dtd < SDP_SEQ8 || sdpdata->dtd > SDP_SEQ32)
+ return sdp_get_uuidseq_attr(rec,
+ SDP_ATTR_SUPPORTED_FEATURES_LIST, seqp);
+
+ for (d = sdpdata->val.dataseq; d; d = d->next) {
+ sdp_data_t *dd;
+ sdp_list_t *subseq;
+
+ if (d->dtd < SDP_SEQ8 || d->dtd > SDP_SEQ32)
+ goto fail;
+
+ subseq = NULL;
+
+ for (dd = d->val.dataseq; dd; dd = dd->next) {
+ sdp_data_t *data;
+ void *val;
+ int length;
+
+ switch (dd->dtd) {
+ case SDP_URL_STR8:
+ case SDP_URL_STR16:
+ case SDP_TEXT_STR8:
+ case SDP_TEXT_STR16:
+ val = dd->val.str;
+ length = dd->unitSize - sizeof(uint8_t);
+ break;
+ case SDP_UINT8:
+ case SDP_UINT16:
+ val = &dd->val;
+ length = 0;
+ break;
+ default:
+ goto fail;
+ }
+
+ data = sdp_data_alloc_with_length(dd->dtd, val, length);
+ if (data)
+ subseq = sdp_list_append(subseq, data);
+ }
+ tseq = sdp_list_append(tseq, subseq);
+ }
+ *seqp = tseq;
+ return 0;
+
+fail:
+ while (tseq) {
+ sdp_list_t * next;
+
+ next = tseq->next;
+ sdp_list_free(tseq, free);
+ tseq = next;
+ }
+ errno = EINVAL;
+ return -1;
+}
+
diff --git a/network/Makefile.am b/network/Makefile.am
deleted file mode 100644
index f5cb320..0000000
--- a/network/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-
-if NETWORKPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = network.la
-
-network_la_SOURCES = main.c manager.h manager.c \
- server.h server.c bridge.h bridge.c \
- connection.h connection.c common.h common.c
-
-LDADD = $(top_builddir)/common/libhelper.a \
- @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden \
- @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = network.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/network/bridge.c b/network/bridge.c
deleted file mode 100644
index 995da5c..0000000
--- a/network/bridge.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * 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 <unistd.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <net/if.h>
-#include <linux/sockios.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/bnep.h>
-
-#include "logging.h"
-#include "bridge.h"
-#include "common.h"
-
-static int bridge_socket = -1;
-static const char *gn_bridge = NULL;
-static const char *nap_bridge = NULL;
-
-int bridge_init(const char *gn_iface, const char *nap_iface)
-{
-#if 0
- struct stat st;
-
- if (stat("/sys/module/bridge", &st) < 0)
- return -EOPNOTSUPP;
-#endif
- bridge_socket = socket(AF_INET, SOCK_STREAM, 0);
- if (bridge_socket < 0) {
- error("Failed to open bridge socket: %s (%d)",
- strerror(errno), errno);
- return -errno;
- }
-
- gn_bridge = gn_iface;
- nap_bridge = nap_iface;
-
- return 0;
-}
-
-void bridge_cleanup(void)
-{
- close(bridge_socket);
-
- bridge_socket = -1;
-}
-
-int bridge_create(int id)
-{
- int err;
- const char *name = bridge_get_name(id);
-
- err = ioctl(bridge_socket, SIOCBRADDBR, name);
- if (err < 0)
- return -errno;
-
- info("bridge %s created", name);
-
- return 0;
-}
-
-int bridge_remove(int id)
-{
- int err;
- const char *name = bridge_get_name(id);
-
- err = bnep_if_down(name);
- if (err < 0)
- return err;
-
- err = ioctl(bridge_socket, SIOCBRDELBR, name);
- if (err < 0)
- return -errno;
-
- info("bridge %s removed", name);
-
- return 0;
-}
-
-int bridge_add_interface(int id, const char *dev)
-{
- struct ifreq ifr;
- int err;
- int ifindex = if_nametoindex(dev);
- const char *name = bridge_get_name(id);
-
- if (!name)
- return -EINVAL;
-
- if (ifindex == 0)
- return -ENODEV;
-
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
- ifr.ifr_ifindex = ifindex;
-
- err = ioctl(bridge_socket, SIOCBRADDIF, &ifr);
- if (err < 0)
- return err;
-
- info("bridge %s: interface %s added", name, dev);
-
- err = bnep_if_up(name, id);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-const char *bridge_get_name(int id)
-{
- if (id == BNEP_SVC_GN)
- return gn_bridge;
-
- if (id == BNEP_SVC_NAP)
- return nap_bridge;
-
- return NULL;
-}
diff --git a/network/bridge.h b/network/bridge.h
deleted file mode 100644
index 272afe2..0000000
--- a/network/bridge.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * 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
- *
- */
-
-int bridge_init(const char *gn_iface, const char *nap_iface);
-void bridge_cleanup(void);
-
-int bridge_create(int id);
-int bridge_remove(int id);
-int bridge_add_interface(int id, const char *dev);
-const char *bridge_get_name(int id);
diff --git a/network/common.c b/network/common.c
index 479716a..ef72679 100644
--- a/network/common.c
+++ b/network/common.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -34,6 +34,7 @@
#include <sys/socket.h>
#include <sys/wait.h>
#include <net/if.h>
+#include <linux/sockios.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
@@ -41,11 +42,10 @@
#include <glib.h>
-#include "logging.h"
+#include "log.h"
#include "common.h"
static int ctl;
-static GSList *pids;
static struct {
const char *name; /* Friendly name */
@@ -58,34 +58,6 @@
{ NULL }
};
-static const char *panu = NULL;
-static const char *gn = NULL;
-static const char *nap = NULL;
-
-struct bnep_data {
- char *devname;
- char *script;
- int pid;
-};
-
-static gint find_devname(gconstpointer a, gconstpointer b)
-{
- struct bnep_data *data = (struct bnep_data *) a;
- const char *devname = b;
-
- return strcmp(data->devname, devname);
-}
-
-static void script_exited(GPid pid, gint status, gpointer data)
-{
- if (WIFEXITED(status))
- debug("%d exited with status %d", pid, WEXITSTATUS(status));
- else
- debug("%d was killed by signal %d", pid, WTERMSIG(status));
-
- g_spawn_close_pid(pid);
-}
-
uint16_t bnep_service_id(const char *svc)
{
int i;
@@ -131,8 +103,7 @@
return NULL;
}
-int bnep_init(const char *panu_script, const char *gn_script,
- const char *nap_script)
+int bnep_init(void)
{
ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
@@ -143,9 +114,6 @@
return -err;
}
- panu = panu_script;
- gn = gn_script;
- nap = nap_script;
return 0;
}
@@ -219,155 +187,76 @@
return 0;
}
-static void bnep_setup(gpointer data)
+int bnep_if_up(const char *devname)
{
-}
-
-static int bnep_exec(const char **argv)
-{
- int pid;
- GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
-
- if (!g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup, NULL,
- &pid, NULL)) {
- error("Unable to execute %s %s", argv[0], argv[1]);
- return -EINVAL;
- }
-
- return pid;
-}
-
-int bnep_if_up(const char *devname, uint16_t id)
-{
- int sd, err;
struct ifreq ifr;
- const char *argv[5];
- struct bnep_data *bnep = NULL;
- GSList *l;
+ int sk, err;
- /* Check if a script is running */
- l = g_slist_find_custom(pids, devname, find_devname);
- if (l) {
- bnep = l->data;
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
- if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
- argv[0] = bnep->script;
- argv[1] = devname;
- argv[2] = "--refresh";
- argv[3] = NULL;
-
- bnep->pid = bnep_exec(argv);
- }
- }
-
- sd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
ifr.ifr_flags |= IFF_UP;
ifr.ifr_flags |= IFF_MULTICAST;
- if ((ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr)) < 0) {
- err = errno;
- error("Could not bring up %s. %s(%d)", devname, strerror(err),
- err);
- return -err;
+ err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
+
+ close(sk);
+
+ if (err < 0) {
+ error("Could not bring up %s", devname);
+ return err;
}
- if (bnep)
- return bnep->pid;
-
- bnep = g_new0(struct bnep_data, 1);
- bnep->devname = g_strdup(devname);
-
- if (!id)
- goto done;
-
- if (id == BNEP_SVC_PANU)
- bnep->script = g_strdup(panu);
- else if (id == BNEP_SVC_GN)
- bnep->script = g_strdup(gn);
- else
- bnep->script = g_strdup(nap);
-
- if (!bnep->script)
- goto done;
-
- argv[0] = bnep->script;
- argv[1] = devname;
-
- if (!strcmp(bnep->script, "avahi-autoipd")) {
- argv[2] = "--no-drop-root";
- argv[3] = "--no-chroot";
- argv[4] = NULL;
- } else
- argv[2] = NULL;
-
- bnep->pid = bnep_exec(argv);
- g_child_watch_add(bnep->pid, script_exited, bnep);
-
-done:
- pids = g_slist_append(pids, bnep);
-
- return bnep->pid;
+ return 0;
}
int bnep_if_down(const char *devname)
{
- int sd, err, pid;
struct ifreq ifr;
- struct bnep_data *bnep;
- GSList *l;
- GSpawnFlags flags;
- const char *argv[4];
+ int sk, err;
- l = g_slist_find_custom(pids, devname, find_devname);
- if (!l)
- return 0;
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
- bnep = l->data;
-
- if (!bnep->pid)
- goto done;
-
- if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
- argv[0] = bnep->script;
- argv[1] = devname;
- argv[2] = "--kill";
- argv[3] = NULL;
-
- flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
- g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup,
- (gpointer) devname, &pid, NULL);
-
- goto done;
- }
-
- /* Kill script */
- err = kill(bnep->pid, SIGTERM);
- if (err < 0)
- error("kill(%d, SIGTERM): %s (%d)", bnep->pid,
- strerror(errno), errno);
-
-done:
- sd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
ifr.ifr_flags &= ~IFF_UP;
/* Bring down the interface */
- ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr);
+ err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
- pids = g_slist_remove(pids, bnep);
+ close(sk);
- if (bnep->devname)
- g_free(bnep->devname);
+ return 0;
+}
- if (bnep->script)
- g_free(bnep->script);
+int bnep_add_to_bridge(const char *devname, const char *bridge)
+{
+ int ifindex = if_nametoindex(devname);
+ struct ifreq ifr;
+ int sk, err;
- g_free(bnep);
+ 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, SIOCBRADDIF, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return err;
+
+ info("bridge %s: interface %s added", bridge, devname);
return 0;
}
diff --git a/network/common.h b/network/common.h
index 424d618..fefb754 100644
--- a/network/common.h
+++ b/network/common.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -26,8 +26,7 @@
#define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
#define BNEP_SVC_UUID "0000000f-0000-1000-8000-00805f9b34fb"
-int bnep_init(const char *panu_script, const char *gn_script,
- const char *nap_script);
+int bnep_init(void);
int bnep_cleanup(void);
uint16_t bnep_service_id(const char *svc);
@@ -38,5 +37,6 @@
int bnep_kill_all_connections(void);
int bnep_connadd(int sk, uint16_t role, char *dev);
-int bnep_if_up(const char *devname, uint16_t id);
+int bnep_if_up(const char *devname);
int bnep_if_down(const char *devname);
+int bnep_add_to_bridge(const char *devname, const char *bridge);
diff --git a/network/connection.c b/network/connection.c
index 7a82467..a255c79 100644
--- a/network/connection.c
+++ b/network/connection.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@
#include <glib.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "glib-helper.h"
#include "btio.h"
#include "dbus-common.h"
@@ -82,7 +82,6 @@
} __attribute__ ((packed));
static DBusConnection *connection = NULL;
-static const char *prefix = NULL;
static GSList *peers = NULL;
static struct network_peer *find_peer(GSList *list, const char *path)
@@ -157,7 +156,7 @@
NETWORK_PEER_INTERFACE, "Connected",
DBUS_TYPE_BOOLEAN, &connected);
emit_property_changed(connection, nc->peer->path,
- NETWORK_PEER_INTERFACE, "Device",
+ NETWORK_PEER_INTERFACE, "Interface",
DBUS_TYPE_STRING, &property);
emit_property_changed(connection, nc->peer->path,
NETWORK_PEER_INTERFACE, "UUID",
@@ -174,8 +173,8 @@
bnep_if_down(nc->dev);
nc->state = DISCONNECTED;
- memset(nc->dev, 0, 16);
- strncpy(nc->dev, prefix, sizeof(nc->dev) - 1);
+ memset(nc->dev, 0, sizeof(nc->dev));
+ strcpy(nc->dev, "bnep%d");
return FALSE;
}
@@ -289,7 +288,7 @@
goto failed;
}
- bnep_if_up(nc->dev, nc->id);
+ bnep_if_up(nc->dev);
pdev = nc->dev;
uuid = bnep_uuid(nc->id);
@@ -302,7 +301,7 @@
NETWORK_PEER_INTERFACE, "Connected",
DBUS_TYPE_BOOLEAN, &connected);
emit_property_changed(connection, nc->peer->path,
- NETWORK_PEER_INTERFACE, "Device",
+ NETWORK_PEER_INTERFACE, "Interface",
DBUS_TYPE_STRING, &pdev);
emit_property_changed(connection, nc->peer->path,
NETWORK_PEER_INTERFACE, "UUID",
@@ -502,9 +501,9 @@
connected = nc ? TRUE : FALSE;
dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
- /* Device */
+ /* Interface */
property = nc ? nc->dev : "";
- dict_append_entry(&dict, "Device", DBUS_TYPE_STRING, &property);
+ dict_append_entry(&dict, "Interface", DBUS_TYPE_STRING, &property);
/* UUID */
property = nc ? bnep_uuid(nc->id) : "";
@@ -539,7 +538,7 @@
{
struct network_peer *peer = data;
- debug("Unregistered interface %s on path %s",
+ DBG("Unregistered interface %s on path %s",
NETWORK_PEER_INTERFACE, peer->path);
peers = g_slist_remove(peers, peer);
@@ -603,7 +602,7 @@
return NULL;
}
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
NETWORK_PEER_INTERFACE, path);
return peer;
@@ -632,8 +631,8 @@
nc = g_new0(struct network_conn, 1);
nc->id = id;
- memset(nc->dev, 0, 16);
- strncpy(nc->dev, prefix, sizeof(nc->dev) - 1);
+ memset(nc->dev, 0, sizeof(nc->dev));
+ strcpy(nc->dev, "bnep%d");
nc->state = DISCONNECTED;
nc->peer = peer;
@@ -642,17 +641,15 @@
return 0;
}
-int connection_init(DBusConnection *conn, const char *iface_prefix)
+int connection_init(DBusConnection *conn)
{
connection = dbus_connection_ref(conn);
- prefix = iface_prefix;
return 0;
}
-void connection_exit()
+void connection_exit(void)
{
dbus_connection_unref(connection);
connection = NULL;
- prefix = NULL;
}
diff --git a/network/connection.h b/network/connection.h
index ba1fdf6..5ea4147 100644
--- a/network/connection.h
+++ b/network/connection.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,8 @@
*
*/
-int connection_init(DBusConnection *conn, const char *iface_prefix);
-void connection_exit();
+int connection_init(DBusConnection *conn);
+void connection_exit(void);
int connection_register(struct btd_device *device, const char *path,
bdaddr_t *src, bdaddr_t *dst, uint16_t id);
void connection_unregister(const char *path, uint16_t id);
diff --git a/network/main.c b/network/main.c
index 97838a2..88e77ee 100644
--- a/network/main.c
+++ b/network/main.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/network/manager.c b/network/manager.c
index bd52279..c910148 100644
--- a/network/manager.c
+++ b/network/manager.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -33,156 +33,43 @@
#include <glib.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "adapter.h"
#include "device.h"
-#include "bridge.h"
#include "manager.h"
#include "common.h"
#include "connection.h"
#include "server.h"
-#define IFACE_PREFIX "bnep%d"
-#define GN_IFACE "pan0"
-#define NAP_IFACE "pan1"
-
-static struct btd_adapter_driver network_panu_server_driver;
-static struct btd_adapter_driver network_gn_server_driver;
-static struct btd_adapter_driver network_nap_server_driver;
-
static DBusConnection *connection = NULL;
-static struct network_conf {
- gboolean connection_enabled;
- gboolean server_enabled;
- gboolean security;
- char *iface_prefix;
- char *panu_script;
- char *gn_script;
- char *nap_script;
- char *gn_iface;
- char *nap_iface;
-} conf = {
- .connection_enabled = TRUE,
- .server_enabled = TRUE,
- .security = TRUE,
- .iface_prefix = NULL,
- .panu_script = NULL,
- .gn_script = NULL,
- .nap_script = NULL,
- .gn_iface = NULL,
- .nap_iface = NULL
-};
-
-static void conf_cleanup(void)
-{
- g_free(conf.iface_prefix);
- g_free(conf.panu_script);
- g_free(conf.gn_script);
- g_free(conf.nap_script);
- g_free(conf.gn_iface);
- g_free(conf.nap_iface);
-}
+static gboolean conf_security = TRUE;
static void read_config(const char *file)
{
GKeyFile *keyfile;
GError *err = NULL;
- char **disabled;
keyfile = g_key_file_new();
if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
- error("Parsing %s failed: %s", file, err->message);
g_clear_error(&err);
goto done;
}
- disabled = g_key_file_get_string_list(keyfile, "General",
- "Disable", NULL, &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_clear_error(&err);
- } else {
- int i;
- for (i = 0; disabled[i] != NULL; i++) {
- if (g_str_equal(disabled[i], "Connection"))
- conf.connection_enabled = FALSE;
- else if (g_str_equal(disabled[i], "Server"))
- conf.server_enabled = FALSE;
- }
- g_strfreev(disabled);
- }
-
- conf.security = !g_key_file_get_boolean(keyfile, "General",
+ conf_security = !g_key_file_get_boolean(keyfile, "General",
"DisableSecurity", &err);
if (err) {
- debug("%s: %s", file, err->message);
- g_clear_error(&err);
- }
-
-#if 0
- conf.panu_script = g_key_file_get_string(keyfile, "PANU Role",
- "Script", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_clear_error(&err);
- }
-
- conf.gn_script = g_key_file_get_string(keyfile, "GN Role",
- "Script", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_clear_error(&err);
- }
-
- conf.nap_script = g_key_file_get_string(keyfile, "NAP Role",
- "Script", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_clear_error(&err);
- }
-#endif
-
- conf.iface_prefix = g_key_file_get_string(keyfile, "PANU Role",
- "Interface", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_clear_error(&err);
- }
-
- conf.gn_iface = g_key_file_get_string(keyfile, "GN Role",
- "Interface", &err);
- if (err) {
- debug("%s: %s", file, err->message);
- g_clear_error(&err);
- }
-
- conf.nap_iface = g_key_file_get_string(keyfile, "NAP Role",
- "Interface", &err);
- if (err) {
- debug("%s: %s", file, err->message);
+ DBG("%s: %s", file, err->message);
g_clear_error(&err);
}
done:
g_key_file_free(keyfile);
- if (!conf.iface_prefix)
- conf.iface_prefix = g_strdup(IFACE_PREFIX);
-
- if (!conf.gn_iface)
- conf.gn_iface = g_strdup(GN_IFACE);
- if (!conf.nap_iface)
- conf.nap_iface = g_strdup(NAP_IFACE);
-
- debug("Config options: InterfacePrefix=%s, PANU_Script=%s, "
- "GN_Script=%s, NAP_Script=%s, GN_Interface=%s, "
- "NAP_Interface=%s, Security=%s",
- conf.iface_prefix, conf.panu_script, conf.gn_script,
- conf.nap_script, conf.gn_iface, conf.nap_iface,
- conf.security ? "true" : "false");
+ DBG("Config options: Security=%s",
+ conf_security ? "true" : "false");
}
static int network_probe(struct btd_device *device, GSList *uuids, uint16_t id)
@@ -238,55 +125,22 @@
network_remove(device, BNEP_SVC_NAP);
}
-static int network_server_probe(struct btd_adapter *adapter, uint16_t id)
+static int network_server_probe(struct btd_adapter *adapter)
{
const gchar *path = adapter_get_path(adapter);
DBG("path %s", path);
- if (!conf.server_enabled)
- return 0;
-
- return server_register(adapter, id);
+ return server_register(adapter);
}
-static void network_server_remove(struct btd_adapter *adapter, uint16_t id)
+static void network_server_remove(struct btd_adapter *adapter)
{
const gchar *path = adapter_get_path(adapter);
DBG("path %s", path);
- server_unregister(adapter, id);
-}
-
-static int panu_server_probe(struct btd_adapter *adapter)
-{
- return network_server_probe(adapter, BNEP_SVC_PANU);
-}
-
-static int gn_server_probe(struct btd_adapter *adapter)
-{
- return network_server_probe(adapter, BNEP_SVC_GN);
-}
-
-static int nap_server_probe(struct btd_adapter *adapter)
-{
- return network_server_probe(adapter, BNEP_SVC_NAP);
-}
-
-static void panu_server_remove(struct btd_adapter *adapter)
-{
- network_server_remove(adapter, BNEP_SVC_PANU);
-}
-
-static void gn_server_remove(struct btd_adapter *adapter)
-{
- network_server_remove(adapter, BNEP_SVC_GN);
-}
-
-static void nap_server_remove(struct btd_adapter *adapter)
-{
- network_server_remove(adapter, BNEP_SVC_NAP);
+ server_unregister(adapter);
}
static struct btd_device_driver network_panu_driver = {
@@ -310,29 +164,17 @@
.remove = nap_remove,
};
-static struct btd_adapter_driver network_panu_server_driver = {
- .name = "network-panu-server",
- .probe = panu_server_probe,
- .remove = panu_server_remove,
-};
-
-static struct btd_adapter_driver network_gn_server_driver = {
- .name = "network-gn-server",
- .probe = gn_server_probe,
- .remove = gn_server_remove,
-};
-
-static struct btd_adapter_driver network_nap_server_driver = {
- .name = "network-nap-server",
- .probe = nap_server_probe,
- .remove = nap_server_remove,
+static struct btd_adapter_driver network_server_driver = {
+ .name = "network-server",
+ .probe = network_server_probe,
+ .remove = network_server_remove,
};
int network_manager_init(DBusConnection *conn)
{
read_config(CONFIGDIR "/network.conf");
- if (bnep_init(conf.panu_script, conf.gn_script, conf.nap_script)) {
+ if (bnep_init()) {
error("Can't init bnep module");
return -1;
}
@@ -343,20 +185,14 @@
* (setup connection request) contains the destination service
* field that defines which service the source is connecting to.
*/
- if (bridge_init(conf.gn_iface, conf.nap_iface) < 0) {
- error("Can't init bridge module");
- return -1;
- }
- if (server_init(conn, conf.iface_prefix, conf.security) < 0)
+ if (server_init(conn, conf_security) < 0)
return -1;
- /* Register PANU, GN and NAP servers if they don't exist */
- btd_register_adapter_driver(&network_panu_server_driver);
- btd_register_adapter_driver(&network_gn_server_driver);
- btd_register_adapter_driver(&network_nap_server_driver);
+ /* Register network server if it doesn't exist */
+ btd_register_adapter_driver(&network_server_driver);
- if (connection_init(conn, conf.iface_prefix) < 0)
+ if (connection_init(conn) < 0)
return -1;
btd_register_device_driver(&network_panu_driver);
@@ -370,24 +206,18 @@
void network_manager_exit(void)
{
- if (conf.server_enabled)
- server_exit();
+ server_exit();
- if (conf.connection_enabled) {
- btd_unregister_device_driver(&network_panu_driver);
- btd_unregister_device_driver(&network_gn_driver);
- btd_unregister_device_driver(&network_nap_driver);
- connection_exit();
- }
+ btd_unregister_device_driver(&network_panu_driver);
+ btd_unregister_device_driver(&network_gn_driver);
+ btd_unregister_device_driver(&network_nap_driver);
- btd_unregister_adapter_driver(&network_panu_server_driver);
- btd_unregister_adapter_driver(&network_gn_server_driver);
- btd_unregister_adapter_driver(&network_nap_server_driver);
+ connection_exit();
+
+ btd_unregister_adapter_driver(&network_server_driver);
dbus_connection_unref(connection);
connection = NULL;
bnep_cleanup();
- bridge_cleanup();
- conf_cleanup();
}
diff --git a/network/manager.h b/network/manager.h
index e26d60b..27bc13f 100644
--- a/network/manager.h
+++ b/network/manager.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/network/network.conf b/network/network.conf
index 4c24c8d..5f11639 100644
--- a/network/network.conf
+++ b/network/network.conf
@@ -1,33 +1,6 @@
# Configuration file for the network service
-# This section contains options which are not specific to any
-# particular interface
[General]
# Disable link encryption: default=false
#DisableSecurity=true
-
-[PANU Role]
-
-# Network interface name for PANU for connections. default:bnep%d
-# (up to 16 characters)
-#Interface=
-
-# PAN user connection interface up script. default:none
-Script=avahi-autoipd
-
-[GN Role]
-
-# Network Interface name for Group Network server. default:pan0
-#Interface=
-
-# Group Network connection interface up script. default:none
-Script=avahi-autoipd
-
-[NAP Role]
-
-# Network Interface name for Network Access Point server. default:pan1
-#Interface=
-
-# Network Access Point connection interface up script. default:none
-Script=dhclient
diff --git a/network/server.c b/network/server.c
index 23d3b64..9a5bd38 100644
--- a/network/server.c
+++ b/network/server.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -44,19 +44,16 @@
#include "../src/dbus-common.h"
#include "../src/adapter.h"
-#include "logging.h"
+#include "log.h"
#include "error.h"
#include "sdpd.h"
#include "btio.h"
#include "glib-helper.h"
-#include "bridge.h"
#include "common.h"
#include "server.h"
-#define NETWORK_PEER_INTERFACE "org.bluez.NetworkPeer"
-#define NETWORK_HUB_INTERFACE "org.bluez.NetworkHub"
-#define NETWORK_ROUTER_INTERFACE "org.bluez.NetworkRouter"
+#define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer"
#define SETUP_TIMEOUT 1
/* Pending Authorization */
@@ -78,17 +75,16 @@
bdaddr_t src; /* Bluetooth Local Address */
char *iface; /* DBus interface */
char *name; /* Server service name */
- char *range; /* IP Address range */
- gboolean enable; /* Enable flag */
+ char *bridge; /* Bridge name */
uint32_t record_id; /* Service record id */
uint16_t id; /* Service class identifier */
GSList *sessions; /* Active connections */
struct network_adapter *na; /* Adapter reference */
+ guint watch_id; /* Client service watch */
};
static DBusConnection *connection = NULL;
static GSList *adapters = NULL;
-static const char *prefix = NULL;
static gboolean security = TRUE;
static struct network_adapter *find_adapter(GSList *list,
@@ -145,7 +141,7 @@
uint16_t security_desc = (security ? 0x0001 : 0x0000);
uint16_t net_access_type = 0xfffe;
uint32_t max_net_access_rate = 0;
- const char *desc = "BlueZ PAN service";
+ const char *desc = "Network service";
sdp_record_t *record;
record = sdp_record_alloc();
@@ -276,15 +272,10 @@
uint16_t dst_role)
{
char devname[16];
- const char *bridge;
int err, nsk;
- /* Server can be disabled in the meantime */
- if (ns->enable == FALSE)
- return -EPERM;
-
- memset(devname, 0, 16);
- strncpy(devname, prefix, sizeof(devname) - 1);
+ memset(devname, 0, sizeof(devname));
+ strcpy(devname, "bnep%d");
nsk = g_io_channel_unix_get_fd(session->io);
err = bnep_connadd(nsk, dst_role, devname);
@@ -293,18 +284,13 @@
info("Added new connection: %s", devname);
- bridge = bridge_get_name(ns->id);
- if (bridge) {
- if (bridge_add_interface(ns->id, devname) < 0) {
- error("Can't add %s to the bridge %s: %s(%d)",
- devname, bridge, strerror(errno),
- errno);
- return -EPERM;
- }
+ if (bnep_add_to_bridge(devname, ns->bridge) < 0) {
+ error("Can't add %s to the bridge %s: %s(%d)",
+ devname, ns->bridge, strerror(errno), errno);
+ return -EPERM;
+ }
- bnep_if_up(devname, 0);
- } else
- bnep_if_up(devname, ns->id);
+ bnep_if_up(devname);
ns->sessions = g_slist_append(ns->sessions, session);
@@ -322,8 +308,8 @@
return BNEP_CONN_INVALID_SRC;
case BNEP_SVC_PANU:
if (src_role == BNEP_SVC_PANU ||
- src_role == BNEP_SVC_GN ||
- src_role == BNEP_SVC_NAP)
+ src_role == BNEP_SVC_GN ||
+ src_role == BNEP_SVC_NAP)
return 0;
return BNEP_CONN_INVALID_SRC;
@@ -422,11 +408,21 @@
goto reply;
ns = find_server(na->servers, dst_role);
- if (!ns || ns->enable == FALSE) {
+ if (!ns) {
error("Server unavailable: (0x%x)", dst_role);
goto reply;
}
+ if (!ns->record_id) {
+ error("Service record not available");
+ goto reply;
+ }
+
+ if (!ns->bridge) {
+ error("Bridge interface not configured");
+ goto reply;
+ }
+
if (server_connadd(ns, na->setup, dst_role) < 0)
goto reply;
@@ -484,6 +480,7 @@
static void confirm_event(GIOChannel *chan, gpointer user_data)
{
struct network_adapter *na = user_data;
+ struct network_server *ns;
int perr;
bdaddr_t src, dst;
char address[18];
@@ -500,13 +497,23 @@
goto drop;
}
- debug("BNEP: incoming connect from %s", address);
+ DBG("BNEP: incoming connect from %s", address);
if (na->setup) {
error("Refusing connect from %s: setup in progress", address);
goto drop;
}
+ ns = find_server(na->servers, BNEP_SVC_NAP);
+ if (!ns)
+ goto drop;
+
+ if (!ns->record_id)
+ goto drop;
+
+ if (!ns->bridge)
+ goto drop;
+
na->setup = g_new0(struct network_session, 1);
bacpy(&na->setup->dst, &dst);
na->setup->io = g_io_channel_ref(chan);
@@ -526,24 +533,16 @@
g_io_channel_shutdown(chan, TRUE, NULL);
}
-int server_init(DBusConnection *conn, const char *iface_prefix,
- gboolean secure)
+int server_init(DBusConnection *conn, gboolean secure)
{
security = secure;
connection = dbus_connection_ref(conn);
- prefix = iface_prefix;
-
- if (bridge_create(BNEP_SVC_GN) < 0)
- error("Can't create GN bridge");
return 0;
}
-void server_exit()
+void server_exit(void)
{
- if (bridge_remove(BNEP_SVC_GN) < 0)
- error("Can't remove GN bridge");
-
dbus_connection_unref(connection);
connection = NULL;
}
@@ -564,7 +563,7 @@
return 0;
}
- debug("register_server_record: got record id 0x%x", record->handle);
+ DBG("got record id 0x%x", record->handle);
return record->handle;
}
@@ -583,164 +582,79 @@
description);
}
-static DBusMessage *enable(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static void server_disconnect(DBusConnection *conn, void *user_data)
{
- struct network_server *ns = data;
- DBusMessage *reply;
+ struct network_server *ns = user_data;
- if (ns->enable)
- return g_dbus_create_error(msg, ERROR_INTERFACE
- ".AlreadyExist",
- "Server already enabled");
+ ns->watch_id = 0;
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- /* Add the service record */
- ns->record_id = register_server_record(ns);
- if (!ns->record_id) {
- dbus_message_unref(reply);
- return failed(msg, "Service record registration failed");
- }
-
- ns->enable = TRUE;
-
- return reply;
-}
-
-static DBusMessage *disable(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct network_server *ns = data;
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (!ns->enable)
- return failed(msg, "Not enabled");
-
- /* Remove the service record */
if (ns->record_id) {
remove_record_from_server(ns->record_id);
ns->record_id = 0;
}
- ns->enable = FALSE;
-
- g_slist_foreach(ns->sessions, (GFunc) session_free, NULL);
- g_slist_free(ns->sessions);
-
- return reply;
+ g_free(ns->bridge);
+ ns->bridge = NULL;
}
-static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
- const char *name, void *data)
-{
- struct network_server *ns = data;
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- if (!name || (strlen(name) == 0))
- return invalid_arguments(msg, "Invalid name");
-
- if (ns->name)
- g_free(ns->name);
- ns->name = g_strdup(name);
-
- if (ns->enable && ns->record_id) {
- uint32_t handle = register_server_record(ns);
- if (!handle) {
- dbus_message_unref(reply);
- return failed(msg,
- "Service record attribute update failed");
- }
-
- remove_record_from_server(ns->record_id);
- ns->record_id = handle;
- }
-
- return reply;
-}
-
-static DBusMessage *get_properties(DBusConnection *conn,
+static DBusMessage *register_server(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct network_server *ns = data;
DBusMessage *reply;
- DBusMessageIter iter;
- DBusMessageIter dict;
- const char *uuid;
+ const char *uuid, *bridge;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (g_strcmp0(uuid, "nap"))
+ return failed(msg, "Invalid UUID");
+
+ if (ns->record_id)
+ return failed(msg, "Already registered");
reply = dbus_message_new_method_return(msg);
if (!reply)
return NULL;
- dbus_message_iter_init_append(reply, &iter);
+ ns->record_id = register_server_record(ns);
+ if (!ns->record_id)
+ return failed(msg, "SDP record registration failed");
- 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_free(ns->bridge);
+ ns->bridge = g_strdup(bridge);
- dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ns->name);
-
- uuid = bnep_uuid(ns->id);
- dict_append_entry(&dict, "Uuid", DBUS_TYPE_STRING, &uuid);
-
- dict_append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &ns->enable);
-
- dbus_message_iter_close_container(&iter, &dict);
+ ns->watch_id = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ server_disconnect, ns, NULL);
return reply;
}
-static DBusMessage *set_property(DBusConnection *conn,
+static DBusMessage *unregister_server(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- DBusMessageIter iter;
- DBusMessageIter sub;
- const char *property;
+ struct network_server *ns = data;
+ DBusMessage *reply;
+ const char *uuid;
- if (!dbus_message_iter_init(msg, &iter))
- return invalid_arguments(msg, "Not a dict");
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID))
+ return NULL;
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- return invalid_arguments(msg, "Key not a string");
+ if (g_strcmp0(uuid, "nap"))
+ return failed(msg, "Invalid UUID");
- dbus_message_iter_get_basic(&iter, &property);
- dbus_message_iter_next(&iter);
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- return invalid_arguments(msg, "Value not a variant");
- dbus_message_iter_recurse(&iter, &sub);
+ g_dbus_remove_watch(conn, ns->watch_id);
- if (g_str_equal("Name", property)) {
- const char *name;
+ server_disconnect(conn, ns);
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
- return invalid_arguments(msg, "Value not string");
- dbus_message_iter_get_basic(&sub, &name);
-
- return set_name(conn, msg, name, data);
- } else if (g_str_equal("Enabled", property)) {
- gboolean enabled;
-
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
- return invalid_arguments(msg, "Value not boolean");
- dbus_message_iter_get_basic(&sub, &enabled);
-
- return enabled ? enable(conn, msg, data) :
- disable(conn, msg, data);
- }
-
- return invalid_arguments(msg, "Property does not exist");
+ return reply;
}
static void adapter_free(struct network_adapter *na)
@@ -764,14 +678,9 @@
if (ns->record_id)
remove_record_from_server(ns->record_id);
- if (ns->iface)
- g_free(ns->iface);
-
- if (ns->name)
- g_free(ns->name);
-
- if (ns->range)
- g_free(ns->range);
+ g_free(ns->iface);
+ g_free(ns->name);
+ g_free(ns->bridge);
if (ns->sessions) {
g_slist_foreach(ns->sessions, (GFunc) session_free, NULL);
@@ -786,7 +695,7 @@
struct network_server *ns = data;
struct network_adapter *na = ns->na;
- debug("Unregistered interface %s on path %s",
+ DBG("Unregistered interface %s on path %s",
ns->iface, adapter_get_path(na->adapter));
na->servers = g_slist_remove(na->servers, ns);
@@ -800,13 +709,8 @@
}
static GDBusMethodTable server_methods[] = {
- { "SetProperty", "sv", "", set_property },
- { "GetProperties", "", "a{sv}",get_properties },
- { }
-};
-
-static GDBusSignalTable server_signals[] = {
- { "PropertyChanged", "sv" },
+ { "Register", "ss", "", register_server },
+ { "Unregister", "s", "", unregister_server },
{ }
};
@@ -840,7 +744,7 @@
return na;
}
-int server_register(struct btd_adapter *adapter, uint16_t id)
+int server_register(struct btd_adapter *adapter)
{
struct network_adapter *na;
struct network_server *ns;
@@ -854,31 +758,19 @@
adapters = g_slist_append(adapters, na);
}
- ns = find_server(na->servers, id);
+ ns = find_server(na->servers, BNEP_SVC_NAP);
if (ns)
return 0;
ns = g_new0(struct network_server, 1);
- switch (id) {
- case BNEP_SVC_PANU:
- ns->iface = g_strdup(NETWORK_PEER_INTERFACE);
- ns->name = g_strdup("BlueZ PANU service");
- break;
- case BNEP_SVC_GN:
- ns->iface = g_strdup(NETWORK_HUB_INTERFACE);
- ns->name = g_strdup("BlueZ GN service");
- break;
- case BNEP_SVC_NAP:
- ns->iface = g_strdup(NETWORK_ROUTER_INTERFACE);
- ns->name = g_strdup("BlueZ NAP service");
- break;
- }
+ ns->iface = g_strdup(NETWORK_SERVER_INTERFACE);
+ ns->name = g_strdup("Network service");
path = adapter_get_path(adapter);
if (!g_dbus_register_interface(connection, path, ns->iface,
- server_methods, server_signals, NULL,
+ server_methods, NULL, NULL,
ns, path_unregister)) {
error("D-Bus failed to register %s interface",
ns->iface);
@@ -887,21 +779,21 @@
}
adapter_get_address(adapter, &ns->src);
- ns->id = id;
+ ns->id = BNEP_SVC_NAP;
ns->na = na;
- ns->record_id = register_server_record(ns);
- ns->enable = TRUE;
+ ns->record_id = 0;
na->servers = g_slist_append(na->servers, ns);
- debug("Registered interface %s on path %s", ns->iface, path);
+ DBG("Registered interface %s on path %s", ns->iface, path);
return 0;
}
-int server_unregister(struct btd_adapter *adapter, uint16_t id)
+int server_unregister(struct btd_adapter *adapter)
{
struct network_adapter *na;
struct network_server *ns;
+ uint16_t id = BNEP_SVC_NAP;
na = find_adapter(adapters, adapter);
if (!na)
diff --git a/network/server.h b/network/server.h
index 5072c47..d88acab 100644
--- a/network/server.h
+++ b/network/server.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -21,14 +21,9 @@
*
*/
-int server_init(DBusConnection *conn, const char *iface_prefix,
- gboolean secure);
-void server_exit();
-int server_register(struct btd_adapter *adapter, uint16_t id);
-int server_unregister(struct btd_adapter *adapter, uint16_t id);
-int server_register_from_file(const char *path, const bdaddr_t *src,
- uint16_t id, const char *filename);
-
-int server_store(const char *path);
+int server_init(DBusConnection *conn, gboolean secure);
+void server_exit(void);
+int server_register(struct btd_adapter *adapter);
+int server_unregister(struct btd_adapter *adapter);
int server_find_data(const char *path, const char *pattern);
diff --git a/plugins/Android.mk b/plugins/Android.mk
index 6302d00..da2b4a6 100755
--- a/plugins/Android.mk
+++ b/plugins/Android.mk
@@ -10,12 +10,11 @@
hciops.c \
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" \
+ -DVERSION=\"4.69\" \
-DBLUETOOTH_PLUGIN_BUILTIN \
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
$(LOCAL_PATH)/../gdbus \
$(LOCAL_PATH)/../src \
$(call include-path-for, glib) \
@@ -28,7 +27,6 @@
libdbus
LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static \
libglib_static
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/bluez-plugin
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
deleted file mode 100644
index 9d9f970..0000000
--- a/plugins/Makefile.am
+++ /dev/null
@@ -1,71 +0,0 @@
-
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES =
-
-builtin_modules =
-builtin_sources =
-builtin_cflags =
-
-if SERVICEPLUGIN
-builtin_modules += service
-builtin_sources += service.c
-endif
-
-builtin_modules += hciops
-builtin_sources += hciops.c
-
-if NETLINK
-plugin_LTLIBRARIES += netlink.la
-netlink_la_LIBADD = @NETLINK_LIBS@
-endif
-
-builtin_modules += hal
-builtin_sources += hal.c
-
-builtin_modules += storage
-builtin_sources += storage.c
-
-noinst_LTLIBRARIES = libbuiltin.la echo.la
-
-libbuiltin_la_SOURCES = $(builtin_sources)
-libbuiltin_la_LDFLAGS =
-libbuiltin_la_CFLAGS = $(AM_CFLAGS) \
- $(builtin_cflags) -DBLUETOOTH_PLUGIN_BUILTIN
-
-BUILT_SOURCES = builtin.h
-
-nodist_libbuiltin_la_SOURCES = $(BUILT_SOURCES)
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ \
- @GLIB_CFLAGS@ @GDBUS_CFLAGS@ @NETLINK_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-CLEANFILES = $(BUILT_SOURCES)
-
-MAINTAINERCLEANFILES = Makefile.in
-
-builtin.h:
- echo "" > $@
- list='$(builtin_modules)'; for i in $$list; \
- do echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$$i;" >> $@; done
- echo "" >> $@
- echo "static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {" >> $@
- list='$(builtin_modules)'; for i in $$list; \
- do echo "&__bluetooth_builtin_$$i," >> $@; done
- echo "NULL };" >> $@
-
-all-local:
- @$(LN_S) -f $(top_srcdir)/input/.libs/input.so
- @$(LN_S) -f $(top_srcdir)/audio/.libs/audio.so
- @$(LN_S) -f $(top_srcdir)/serial/.libs/serial.so
- @$(LN_S) -f $(top_srcdir)/network/.libs/network.so
-
-clean-local:
- @rm -f network.so
- @rm -f serial.so
- @rm -f audio.so
- @rm -f input.so
diff --git a/plugins/echo.c b/plugins/echo.c
index 919d085..23f6e49 100644
--- a/plugins/echo.c
+++ b/plugins/echo.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@
#include "plugin.h"
#include "adapter.h"
-#include "logging.h"
+#include "log.h"
static gboolean session_event(GIOChannel *chan,
GIOCondition cond, gpointer data)
@@ -151,14 +151,14 @@
static int echo_init(void)
{
- debug("Setup echo plugin");
+ DBG("Setup echo plugin");
return btd_register_adapter_driver(&echo_server);
}
static void echo_exit(void)
{
- debug("Cleanup echo plugin");
+ DBG("Cleanup echo plugin");
btd_unregister_adapter_driver(&echo_server);
}
diff --git a/plugins/hal.c b/plugins/hal.c
index 6815f28..f6121c5 100644
--- a/plugins/hal.c
+++ b/plugins/hal.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#include "plugin.h"
#include "adapter.h"
-#include "logging.h"
+#include "log.h"
#include "dbus-hci.h"
static void formfactor_reply(DBusPendingCall *call, void *user_data)
@@ -42,8 +42,7 @@
struct btd_adapter *adapter = user_data;
const char *formfactor = NULL;
DBusMessage *reply;
- uint8_t cls[3], minor = 0;
- int dd;
+ uint8_t minor = 0;
reply = dbus_pending_call_steal_reply(call);
@@ -60,7 +59,7 @@
return;
}
- debug("Computer is classified as %s", formfactor);
+ DBG("Computer is classified as %s", formfactor);
if (formfactor != NULL) {
if (g_str_equal(formfactor, "laptop") == TRUE)
@@ -75,24 +74,10 @@
dbus_message_unref(reply);
- dd = hci_open_dev(adapter_get_dev_id(adapter));
- if (dd < 0)
- return;
-
- if (hci_read_class_of_dev(dd, cls, 500) < 0) {
- hci_close_dev(dd);
- return;
- }
-
- debug("Current device class is 0x%02x%02x%02x\n",
- cls[2], cls[1], cls[0]);
-
/* Computer major class */
- debug("Setting 0x%06x for major/minor device class", (1 << 8) | minor);
+ DBG("Setting 0x%06x for major/minor device class", (1 << 8) | minor);
- hci_close_dev(dd);
-
- set_major_and_minor_class(adapter, 0x01, minor);
+ btd_adapter_set_class(adapter, 0x01, minor);
}
static DBusConnection *connection;
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 4df799b..5775cf1 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -26,13 +26,8 @@
#include <stdio.h>
#include <errno.h>
-#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
@@ -43,15 +38,12 @@
#include <glib.h>
-#include <dbus/dbus.h>
-
#include "hcid.h"
#include "sdpd.h"
#include "adapter.h"
#include "plugin.h"
-#include "logging.h"
+#include "log.h"
#include "manager.h"
-#include "storage.h"
static int child_pipe[2] = { -1, -1 };
@@ -71,7 +63,7 @@
if (waitpid(child_pid, &status, 0) != child_pid)
error("waitpid(%d) failed", child_pid);
else
- debug("child %d exited", child_pid);
+ DBG("child %d exited", child_pid);
return TRUE;
}
@@ -84,11 +76,11 @@
error("unable to write to child pipe");
}
-static void configure_device(int index)
+static void device_devup_setup(int index)
{
struct hci_dev_info di;
uint16_t policy;
- int dd;
+ int dd, err;
if (hci_devinfo(index, &di) < 0)
return;
@@ -98,44 +90,12 @@
dd = hci_open_dev(index);
if (dd < 0) {
+ err = errno;
error("Can't open device hci%d: %s (%d)",
- index, strerror(errno), errno);
+ index, strerror(err), err);
return;
}
- /* Set device name */
- if ((main_opts.flags & (1 << HCID_SET_NAME)) && main_opts.name) {
- change_local_name_cp cp;
-
- memset(cp.name, 0, sizeof(cp.name));
- expand_name((char *) cp.name, sizeof(cp.name),
- main_opts.name, index);
-
- hci_send_cmd(dd, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
- CHANGE_LOCAL_NAME_CP_SIZE, &cp);
- }
-
- /* Set device class */
- if ((main_opts.flags & (1 << HCID_SET_CLASS))) {
- write_class_of_dev_cp cp;
- uint32_t class;
- uint8_t cls[3];
-
- if (read_local_class(&di.bdaddr, cls) < 0) {
- class = htobl(main_opts.class);
- cls[2] = get_service_classes(&di.bdaddr);
- memcpy(cp.dev_class, &class, 3);
- } else {
- if (!(main_opts.scan & SCAN_INQUIRY))
- cls[1] &= 0xdf; /* Clear discoverable bit */
- cls[2] = get_service_classes(&di.bdaddr);
- memcpy(cp.dev_class, cls, 3);
- }
-
- hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
- WRITE_CLASS_OF_DEV_CP_SIZE, &cp);
- }
-
/* Set page timeout */
if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
write_page_timeout_cp cp;
@@ -151,6 +111,12 @@
OCF_WRITE_DEFAULT_LINK_POLICY, 2, &policy);
hci_close_dev(dd);
+
+ start_security_manager(index);
+
+ /* Return value 1 means ioctl(DEVDOWN) was performed */
+ if (manager_start_adapter(index) == 1)
+ stop_security_manager(index);
}
static void init_device(int index)
@@ -158,7 +124,7 @@
struct hci_dev_req dr;
struct hci_dev_info di;
pid_t pid;
- int dd;
+ int dd, err;
/* Do initialization in the separate process */
pid = fork();
@@ -167,17 +133,19 @@
atexit(at_child_exit);
break;
case -1:
+ err = errno;
error("Fork failed. Can't init device hci%d: %s (%d)",
- index, strerror(errno), errno);
+ index, strerror(err), err);
default:
- debug("child %d forked", pid);
+ DBG("child %d forked", pid);
return;
}
dd = hci_open_dev(index);
if (dd < 0) {
+ err = errno;
error("Can't open device hci%d: %s (%d)",
- index, strerror(errno), errno);
+ index, strerror(err), err);
exit(1);
}
@@ -187,8 +155,9 @@
/* Set link mode */
dr.dev_opt = main_opts.link_mode;
if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0) {
+ err = errno;
error("Can't set link mode on hci%d: %s (%d)",
- index, strerror(errno), errno);
+ index, strerror(err), err);
}
/* Set link policy */
@@ -239,17 +208,6 @@
manager_register_adapter(index, devup);
}
-static void device_devup_setup(int index)
-{
- configure_device(index);
-
- start_security_manager(index);
-
- /* Return value 1 means ioctl(DEVDOWN) was performed */
- if (manager_start_adapter(index) == 1)
- stop_security_manager(index);
-}
-
static void device_event(int event, int index)
{
switch (event) {
@@ -284,29 +242,27 @@
dl = g_try_malloc0(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
if (!dl) {
- err = -errno;
+ err = errno;
error("Can't allocate devlist buffer: %s (%d)",
- strerror(errno), errno);
- return err;
+ strerror(err), err);
+ return -err;
}
dl->dev_num = HCI_MAX_DEV;
dr = dl->dev_req;
if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
- err = -errno;
+ err = errno;
error("Can't get device list: %s (%d)",
- strerror(errno), errno);
- return err;
+ strerror(err), err);
+ g_free(dl);
+ return -err;
}
for (i = 0; i < dl->dev_num; i++, dr++) {
- gboolean devup;
-
device_event(HCI_DEV_REG, dr->dev_id);
- devup = hci_test_bit(HCI_UP, &dr->dev_opt);
- if (devup)
+ if (hci_test_bit(HCI_UP, &dr->dev_opt))
device_event(HCI_DEV_UP, dr->dev_id);
}
@@ -370,9 +326,9 @@
return -EALREADY;
if (pipe(child_pipe) < 0) {
- err = -errno;
- error("pipe(): %s (%d)", strerror(errno), errno);
- return err;
+ err = errno;
+ error("pipe(): %s (%d)", strerror(err), err);
+ return -err;
}
child_io = g_io_channel_unix_new(child_pipe[0]);
@@ -385,10 +341,10 @@
/* 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(errno),
- errno);
- return err;
+ err = errno;
+ error("Can't open HCI socket: %s (%d)", strerror(err),
+ err);
+ return -err;
}
/* Set filter */
@@ -397,9 +353,9 @@
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(errno), errno);
- return err;
+ err = errno;
+ error("Can't set filter: %s (%d)", strerror(err), err);
+ return -err;
}
memset(&addr, 0, sizeof(addr));
@@ -407,10 +363,10 @@
addr.hci_dev = HCI_DEV_NONE;
if (bind(sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- err = -errno;
+ err = errno;
error("Can't bind HCI socket: %s (%d)",
- strerror(errno), errno);
- return err;
+ strerror(err), err);
+ return -err;
}
ctl_io = g_io_channel_unix_new(sock);
@@ -460,14 +416,14 @@
goto done; /* on success */
if (errno != EALREADY) {
- err = -errno;
+ err = errno;
error("Can't init device hci%d: %s (%d)",
- index, strerror(errno), errno);
+ index, strerror(err), err);
}
done:
hci_close_dev(dd);
- return err;
+ return -err;
}
static int hciops_stop(int index)
@@ -483,19 +439,19 @@
goto done; /* on success */
if (errno != EALREADY) {
- err = -errno;
+ err = errno;
error("Can't stop device hci%d: %s (%d)",
- index, strerror(errno), errno);
+ index, strerror(err), err);
}
done:
hci_close_dev(dd);
- return err;
+ return -err;
}
static int hciops_powered(int index, gboolean powered)
{
- int dd;
+ int dd, err;
uint8_t mode = SCAN_DISABLED;
if (powered)
@@ -505,8 +461,13 @@
if (dd < 0)
return -EIO;
- hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+ err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
1, &mode);
+ if (err < 0) {
+ err = -errno;
+ hci_close_dev(dd);
+ return err;
+ }
hci_close_dev(dd);
@@ -515,45 +476,72 @@
static int hciops_connectable(int index)
{
- int dd;
+ int dd, err;
uint8_t mode = SCAN_PAGE;
dd = hci_open_dev(index);
if (dd < 0)
return -EIO;
- hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+ err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
1, &mode);
+ if (err < 0)
+ err = -errno;
hci_close_dev(dd);
- return 0;
+ return err;
}
static int hciops_discoverable(int index)
{
- int dd;
+ int dd, err;
uint8_t mode = (SCAN_PAGE | SCAN_INQUIRY);
dd = hci_open_dev(index);
if (dd < 0)
return -EIO;
- hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+ err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
1, &mode);
+ if (err < 0)
+ err = -errno;
hci_close_dev(dd);
- return 0;
+ return err;
}
-static int hciops_set_limited_discoverable(int index, const uint8_t *cls,
+static int hciops_set_class(int index, uint32_t class)
+{
+ int dd, err;
+ write_class_of_dev_cp cp;
+
+ dd = hci_open_dev(index);
+ if (dd < 0)
+ return -EIO;
+
+ memcpy(cp.dev_class, &class, 3);
+
+ err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
+ WRITE_CLASS_OF_DEV_CP_SIZE, &cp);
+
+ if (err < 0)
+ err = -errno;
+
+ hci_close_dev(dd);
+
+ return err;
+}
+
+static int hciops_set_limited_discoverable(int index, uint32_t class,
gboolean limited)
{
- int dd, err = 0;
- uint32_t dev_class;
+ int dd, err;
int num = (limited ? 2 : 1);
uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
+ write_current_iac_lap_cp cp;
+
/*
* 1: giac
* 2: giac + liac
@@ -562,40 +550,27 @@
if (dd < 0)
return -EIO;
- if (hci_write_current_iac_lap(dd, num, lap, HCI_REQ_TIMEOUT) < 0) {
+ memset(&cp, 0, sizeof(cp));
+ cp.num_current_iac = num;
+ memcpy(&cp.lap, lap, num * 3);
+
+ err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
+ (num * 3 + 1), &cp);
+ if (err < 0) {
err = -errno;
- error("Can't write current IAC LAP: %s(%d)",
- strerror(errno), errno);
- goto done;
+ hci_close_dev(dd);
+ return err;
}
- if (limited) {
- if (cls[1] & 0x20)
- goto done; /* Already limited */
-
- dev_class = (cls[2] << 16) | ((cls[1] | 0x20) << 8) | cls[0];
- } else {
- if (!(cls[1] & 0x20))
- goto done; /* Already clear */
-
- dev_class = (cls[2] << 16) | ((cls[1] & 0xdf) << 8) | cls[0];
- }
-
- if (hci_write_class_of_dev(dd, dev_class, HCI_REQ_TIMEOUT) < 0) {
- err = -errno;
- error("Can't write class of device: %s (%d)",
- strerror(errno), errno);
- goto done;
- }
-done:
hci_close_dev(dd);
- return err;
+
+ return hciops_set_class(index, class);
}
static int hciops_start_discovery(int index, gboolean periodic)
{
uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
- int dd, err = 0;
+ int dd, err;
dd = hci_open_dev(index);
if (dd < 0)
@@ -636,7 +611,7 @@
static int hciops_stop_discovery(int index)
{
struct hci_dev_info di;
- int dd, err = 0;
+ int dd, err;
if (hci_devinfo(index, &di) < 0)
return -errno;
@@ -662,7 +637,7 @@
static int hciops_resolve_name(int index, bdaddr_t *bdaddr)
{
remote_name_req_cp cp;
- int dd, err = 0;
+ int dd, err;
dd = hci_open_dev(index);
if (dd < 0)
@@ -685,7 +660,7 @@
static int hciops_set_name(int index, const char *name)
{
change_local_name_cp cp;
- int dd, err = 0;
+ int dd, err;
dd = hci_open_dev(index);
if (dd < 0)
@@ -706,7 +681,7 @@
static int hciops_read_name(int index)
{
- int dd, err = 0;
+ int dd, err;
dd = hci_open_dev(index);
if (dd < 0)
@@ -724,7 +699,7 @@
static int hciops_cancel_resolve_name(int index, bdaddr_t *bdaddr)
{
remote_name_req_cancel_cp cp;
- int dd, err = 0;
+ int dd, err;
dd = hci_open_dev(index);
if (dd < 0)
@@ -758,6 +733,7 @@
.cancel_resolve_name = hciops_cancel_resolve_name,
.set_name = hciops_set_name,
.read_name = hciops_read_name,
+ .set_class = hciops_set_class,
};
static int hciops_init(void)
diff --git a/plugins/maemo6.c b/plugins/maemo6.c
new file mode 100644
index 0000000..2ed5f12
--- /dev/null
+++ b/plugins/maemo6.c
@@ -0,0 +1,176 @@
+/*
+ *
+ * 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_GET "get_radio_states"
+#define MCE_RADIO_STATES_SIG "radio_states_ind"
+
+static guint watch_id;
+static DBusConnection *conn = NULL;
+
+static gboolean mce_signal_callback(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ DBusMessageIter args;
+ uint32_t sigvalue;
+ struct btd_adapter *adapter = user_data;
+
+ DBG("received mce signal");
+
+ if (!dbus_message_iter_init(message, &args))
+ error("message has no arguments");
+ else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
+ error("argument is not uint32");
+ else {
+ dbus_message_iter_get_basic(&args, &sigvalue);
+ DBG("got signal with value %u", sigvalue);
+
+ if (sigvalue & MCE_RADIO_STATE_BLUETOOTH)
+ btd_adapter_switch_online(adapter);
+ else
+ btd_adapter_switch_offline(adapter);
+ }
+
+ return TRUE;
+}
+
+static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
+{
+ DBusError err;
+ DBusMessage *reply;
+ dbus_uint32_t radio_states;
+ struct btd_adapter *adapter = user_data;
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, reply)) {
+ error("mce replied with an error: %s, %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args(reply, &err,
+ DBUS_TYPE_UINT32, &radio_states,
+ DBUS_TYPE_INVALID) == FALSE) {
+ error("unable to parse get_radio_states reply: %s, %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ if (radio_states & MCE_RADIO_STATE_BLUETOOTH)
+ btd_adapter_switch_online(adapter);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static int mce_probe(struct btd_adapter *adapter)
+{
+ DBusMessage *msg;
+ DBusPendingCall *call;
+
+ DBG("path %s", adapter_get_path(adapter));
+
+ msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
+ MCE_REQUEST_IF, MCE_RADIO_STATES_GET);
+
+ if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) {
+ error("calling %s failed", MCE_RADIO_STATES_GET);
+ dbus_message_unref(msg);
+ return -1;
+ }
+
+ dbus_pending_call_set_notify(call, read_radio_states_cb, adapter, NULL);
+ dbus_pending_call_unref(call);
+ dbus_message_unref(msg);
+
+ watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
+ MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG,
+ mce_signal_callback, adapter, NULL);
+ return 0;
+}
+
+static void mce_remove(struct btd_adapter *adapter)
+{
+ DBG("path %s", adapter_get_path(adapter));
+
+ if (watch_id > 0)
+ g_dbus_remove_watch(conn, watch_id);
+}
+
+static struct btd_adapter_driver mce_driver = {
+ .name = "mce",
+ .probe = mce_probe,
+ .remove = mce_remove,
+};
+
+static int maemo6_init(void)
+{
+ DBG("init maemo6 plugin");
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (conn == NULL) {
+ error("Unable to connect to D-Bus");
+ return -1;
+ }
+
+ return btd_register_adapter_driver(&mce_driver);
+}
+
+static void maemo6_exit(void)
+{
+ DBG("exit maemo6 plugin");
+
+ if (conn != NULL)
+ dbus_connection_unref(conn);
+
+ btd_unregister_adapter_driver(&mce_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(maemo6, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, maemo6_init, maemo6_exit)
diff --git a/plugins/netlink.c b/plugins/netlink.c
index e85d264..081ffa2 100644
--- a/plugins/netlink.c
+++ b/plugins/netlink.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@
#include <glib.h>
#include "plugin.h"
-#include "logging.h"
+#include "log.h"
static struct nl_handle *handle;
static struct nl_cache *cache;
@@ -53,7 +53,7 @@
if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
return FALSE;
- debug("Message available on netlink channel");
+ DBG("Message available on netlink channel");
err = nl_recvmsgs_default(handle);
@@ -91,8 +91,8 @@
cache = genl_ctrl_alloc_cache(handle);
if (!cache) {
error("Failed to allocate generic netlink cache");
- return -ENOMEM;
nl_handle_destroy(handle);
+ return -ENOMEM;
}
family = genl_ctrl_search_by_name(cache, "bluetooth");
diff --git a/plugins/pnat.c b/plugins/pnat.c
new file mode 100644
index 0000000..f9136a4
--- /dev/null
+++ b/plugins/pnat.c
@@ -0,0 +1,522 @@
+/*
+ *
+ * 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 <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 DUN_UUID "00001103-0000-1000-8000-00805F9B34FB"
+
+#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;
+ guint pnatd_watch;
+};
+
+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;
+
+ g_io_channel_unref(client->io);
+ client->io = NULL;
+
+ if (client->io_watch > 0) {
+ g_source_remove(client->io_watch);
+ client->io_watch = 0;
+ }
+
+ if (client->pnatd_watch > 0) {
+ g_source_remove(client->pnatd_watch);
+ client->pnatd_watch = 0;
+ if (client->pnatd_pid > 0)
+ kill(client->pnatd_pid, SIGTERM);
+ }
+
+ if (client->pnatd_pid > 0) {
+ g_spawn_close_pid(client->pnatd_pid);
+ 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));
+
+ client->pnatd_watch = 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;
+ client->pnatd_watch = 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 dev, 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);
+
+ dev = ioctl(sk, RFCOMMCREATEDEV, &req);
+ if (dev < 0) {
+ error("Can't create RFCOMM TTY: %s", strerror(errno));
+ return FALSE;
+ }
+
+ snprintf(client->tty_name, PATH_MAX - 1, "/dev/rfcomm%d", dev);
+
+ 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_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/service.c b/plugins/service.c
index f89a7d6..96280bd 100644
--- a/plugins/service.c
+++ b/plugins/service.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -43,7 +43,7 @@
#include "plugin.h"
#include "adapter.h"
#include "error.h"
-#include "logging.h"
+#include "log.h"
#define SERVICE_INTERFACE "org.bluez.Service"
@@ -107,7 +107,7 @@
break;
}
}
- debug("New attribute 0x%04x", ctx_data->attr_id);
+ DBG("New attribute 0x%04x", ctx_data->attr_id);
return;
}
@@ -174,13 +174,13 @@
int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
ctx_data->stack_head->data);
if (ret == -1)
- debug("Trouble adding attribute\n");
+ DBG("Trouble adding attribute\n");
ctx_data->stack_head->data = NULL;
sdp_xml_data_free(ctx_data->stack_head);
ctx_data->stack_head = NULL;
} else {
- debug("No data for attribute 0x%04x\n", ctx_data->attr_id);
+ DBG("No data for attribute 0x%04x\n", ctx_data->attr_id);
}
return;
}
@@ -321,7 +321,7 @@
struct service_adapter *serv_adapter = user_record->serv_adapter;
struct pending_auth *auth;
- debug("remove record");
+ DBG("remove record");
serv_adapter->records = g_slist_remove(serv_adapter->records,
user_record);
@@ -409,7 +409,7 @@
serv_adapter->records = g_slist_append(serv_adapter->records,
user_record);
- debug("listener_id %d", user_record->listener_id);
+ DBG("listener_id %d", user_record->listener_id);
*handle = user_record->handle;
@@ -493,13 +493,13 @@
{
struct record_data *user_record;
- debug("remove record 0x%x", handle);
+ DBG("remove record 0x%x", handle);
user_record = find_record(serv_adapter, handle, sender);
if (!user_record)
return -1;
- debug("listner_id %d", user_record->listener_id);
+ DBG("listner_id %d", user_record->listener_id);
g_dbus_remove_watch(conn, user_record->listener_id);
@@ -640,6 +640,8 @@
}
record = sdp_record_find(user_record->handle);
+ if (record == NULL)
+ return not_authorized(msg);
if (sdp_get_service_classes(record, &services) < 0) {
sdp_record_free(record);
@@ -787,7 +789,7 @@
return -EIO;
}
- debug("Registered interface %s on path %s", SERVICE_INTERFACE, path);
+ DBG("Registered interface %s on path %s", SERVICE_INTERFACE, path);
if (serv_adapter->adapter == NULL)
serv_adapter_any = serv_adapter;
diff --git a/plugins/storage.c b/plugins/storage.c
index 99b4952..04a02c7 100644
--- a/plugins/storage.c
+++ b/plugins/storage.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
#include <bluetooth/bluetooth.h>
#include "plugin.h"
-#include "logging.h"
+#include "log.h"
static int storage_init(void)
{
diff --git a/rfcomm/Android.mk b/rfcomm/Android.mk
deleted file mode 100755
index 18e0f8f..0000000
--- a/rfcomm/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- kword.c \
- main.c \
- parser.c \
- lexer.c
-
-LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" \
- -DCONFIGDIR=\"/etc/bluetooth\" \
- -DNEED_PPOLL
-
-LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../common \
- $(LOCAL_PATH)/../include
-
-LOCAL_SHARED_LIBRARIES := \
- libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
-LOCAL_MODULE:=rfcomm
-
-include $(BUILD_EXECUTABLE)
diff --git a/rfcomm/Makefile.am b/rfcomm/Makefile.am
deleted file mode 100644
index 9baa8e6..0000000
--- a/rfcomm/Makefile.am
+++ /dev/null
@@ -1,34 +0,0 @@
-
-if TOOLS
-if CONFIGFILES
-confdir = $(sysconfdir)/bluetooth
-
-conf_DATA = rfcomm.conf
-endif
-
-bin_PROGRAMS = rfcomm
-
-rfcomm_SOURCES = main.c parser.h parser.y lexer.l kword.h kword.c
-
-rfcomm_LDADD = @BLUEZ_LIBS@
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-BUILT_SOURCES = parser.h
-
-if TOOLS
-if MANPAGES
-man_MANS = rfcomm.1
-endif
-endif
-
-AM_YFLAGS = -d
-
-CLEANFILES = lexer.c parser.c parser.h
-
-EXTRA_DIST = rfcomm.1 rfcomm.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/sbc/Makefile.am b/sbc/Makefile.am
deleted file mode 100644
index f870164..0000000
--- a/sbc/Makefile.am
+++ /dev/null
@@ -1,33 +0,0 @@
-
-if SNDFILE
-sndfile_programs = sbctester
-else
-sndfile_programs =
-endif
-
-if SBC
-noinst_LTLIBRARIES = libsbc.la
-
-libsbc_la_SOURCES = sbc.h sbc.c sbc_math.h sbc_tables.h \
- sbc_primitives.h sbc_primitives_mmx.h sbc_primitives_neon.h \
- sbc_primitives.c sbc_primitives_mmx.c sbc_primitives_neon.c
-
-libsbc_la_CFLAGS = -finline-functions -fgcse-after-reload \
- -funswitch-loops -funroll-loops
-
-noinst_PROGRAMS = sbcinfo sbcdec sbcenc $(sndfile_programs)
-
-sbcdec_SOURCES = sbcdec.c formats.h
-sbcdec_LDADD = libsbc.la
-
-sbcenc_SOURCES = sbcenc.c formats.h
-sbcenc_LDADD = libsbc.la
-
-if SNDFILE
-sbctester_LDADD = @SNDFILE_LIBS@
-endif
-endif
-
-AM_CFLAGS = @SNDFILE_CFLAGS@
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/sbc/formats.h b/sbc/formats.h
index 6c1960d..3050b25 100644
--- a/sbc/formats.h
+++ b/sbc/formats.h
@@ -2,7 +2,7 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/sbc/sbc.c b/sbc/sbc.c
index 14e5869..a6391ae 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
@@ -77,7 +78,7 @@
uint8_t joint;
/* only the lower 4 bits of every element are to be used */
- uint32_t scale_factor[2][8];
+ uint32_t SBC_ALIGNED scale_factor[2][8];
/* raw integer subband samples in the frame */
int32_t SBC_ALIGNED sb_sample_f[16][2][8];
@@ -159,7 +160,8 @@
* Takes a pointer to the frame in question, a pointer to the bits array and
* the sampling frequency (as 2 bit integer)
*/
-static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
+ const struct sbc_frame *frame, int (*bits)[8], int subbands)
{
uint8_t sf = frame->frequency;
@@ -170,17 +172,17 @@
for (ch = 0; ch < frame->channels; ch++) {
max_bitneed = 0;
if (frame->allocation == SNR) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
bitneed[ch][sb] = frame->scale_factor[ch][sb];
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
}
} else {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (frame->scale_factor[ch][sb] == 0)
bitneed[ch][sb] = -5;
else {
- if (frame->subbands == 4)
+ if (subbands == 4)
loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
else
loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -201,7 +203,7 @@
bitslice--;
bitcount += slicecount;
slicecount = 0;
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
slicecount++;
else if (bitneed[ch][sb] == bitslice + 1)
@@ -214,7 +216,7 @@
bitslice--;
}
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (bitneed[ch][sb] < bitslice + 2)
bits[ch][sb] = 0;
else {
@@ -224,7 +226,8 @@
}
}
- for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ for (sb = 0; bitcount < frame->bitpool &&
+ sb < subbands; sb++) {
if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
bits[ch][sb]++;
bitcount++;
@@ -234,7 +237,8 @@
}
}
- for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ for (sb = 0; bitcount < frame->bitpool &&
+ sb < subbands; sb++) {
if (bits[ch][sb] < 16) {
bits[ch][sb]++;
bitcount++;
@@ -250,7 +254,7 @@
max_bitneed = 0;
if (frame->allocation == SNR) {
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
bitneed[ch][sb] = frame->scale_factor[ch][sb];
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
@@ -258,11 +262,11 @@
}
} else {
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (frame->scale_factor[ch][sb] == 0)
bitneed[ch][sb] = -5;
else {
- if (frame->subbands == 4)
+ if (subbands == 4)
loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
else
loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -285,7 +289,7 @@
bitcount += slicecount;
slicecount = 0;
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
slicecount++;
else if (bitneed[ch][sb] == bitslice + 1)
@@ -300,7 +304,7 @@
}
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (bitneed[ch][sb] < bitslice + 2) {
bits[ch][sb] = 0;
} else {
@@ -324,7 +328,8 @@
if (ch == 1) {
ch = 0;
sb++;
- if (sb >= frame->subbands) break;
+ if (sb >= subbands)
+ break;
} else
ch = 1;
}
@@ -339,7 +344,8 @@
if (ch == 1) {
ch = 0;
sb++;
- if (sb >= frame->subbands) break;
+ if (sb >= subbands)
+ break;
} else
ch = 1;
}
@@ -348,6 +354,14 @@
}
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+ if (frame->subbands == 4)
+ sbc_calculate_bits_internal(frame, bits, 4);
+ else
+ sbc_calculate_bits_internal(frame, bits, 8);
+}
+
/*
* Unpacks a SBC frame at the beginning of the stream in data,
* which has at most len bytes into frame.
@@ -742,9 +756,10 @@
* -99 not implemented
*/
-static SBC_ALWAYS_INLINE int sbc_pack_frame_internal(uint8_t *data,
+static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data,
struct sbc_frame *frame, size_t len,
- int frame_subbands, int frame_channels)
+ int frame_subbands, int frame_channels,
+ int joint)
{
/* Bitstream writer starts from the fourth byte */
uint8_t *data_ptr = data + 4;
@@ -801,63 +816,6 @@
crc_pos = 16;
if (frame->mode == JOINT_STEREO) {
- /* like frame->sb_sample but joint stereo */
- int32_t sb_sample_j[16][2];
- /* scalefactor and scale_factor in joint case */
- uint32_t scalefactor_j[2];
- uint8_t scale_factor_j[2];
-
- uint8_t joint = 0;
- frame->joint = 0;
-
- for (sb = 0; sb < frame_subbands - 1; sb++) {
- scale_factor_j[0] = 0;
- scalefactor_j[0] = 2 << SCALE_OUT_BITS;
- scale_factor_j[1] = 0;
- scalefactor_j[1] = 2 << SCALE_OUT_BITS;
-
- for (blk = 0; blk < frame->blocks; blk++) {
- uint32_t tmp;
- /* Calculate joint stereo signal */
- sb_sample_j[blk][0] =
- ASR(frame->sb_sample_f[blk][0][sb], 1) +
- ASR(frame->sb_sample_f[blk][1][sb], 1);
- sb_sample_j[blk][1] =
- ASR(frame->sb_sample_f[blk][0][sb], 1) -
- ASR(frame->sb_sample_f[blk][1][sb], 1);
-
- /* calculate scale_factor_j and scalefactor_j for joint case */
- tmp = fabs(sb_sample_j[blk][0]);
- while (scalefactor_j[0] < tmp) {
- scale_factor_j[0]++;
- scalefactor_j[0] *= 2;
- }
- tmp = fabs(sb_sample_j[blk][1]);
- while (scalefactor_j[1] < tmp) {
- scale_factor_j[1]++;
- scalefactor_j[1] *= 2;
- }
- }
-
- /* decide whether to join this subband */
- if ((frame->scale_factor[0][sb] +
- frame->scale_factor[1][sb]) >
- (scale_factor_j[0] +
- scale_factor_j[1])) {
- /* use joint stereo for this subband */
- joint |= 1 << (frame_subbands - 1 - sb);
- frame->joint |= 1 << sb;
- frame->scale_factor[0][sb] = scale_factor_j[0];
- frame->scale_factor[1][sb] = scale_factor_j[1];
- for (blk = 0; blk < frame->blocks; blk++) {
- frame->sb_sample_f[blk][0][sb] =
- sb_sample_j[blk][0];
- frame->sb_sample_f[blk][1][sb] =
- sb_sample_j[blk][1];
- }
- }
- }
-
PUT_BITS(data_ptr, bits_cache, bits_count,
joint, frame_subbands);
crc_header[crc_pos >> 3] = joint;
@@ -915,18 +873,23 @@
return data_ptr - data;
}
-static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len)
+static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len,
+ int joint)
{
if (frame->subbands == 4) {
if (frame->channels == 1)
- return sbc_pack_frame_internal(data, frame, len, 4, 1);
+ return sbc_pack_frame_internal(
+ data, frame, len, 4, 1, joint);
else
- return sbc_pack_frame_internal(data, frame, len, 4, 2);
+ return sbc_pack_frame_internal(
+ data, frame, len, 4, 2, joint);
} else {
if (frame->channels == 1)
- return sbc_pack_frame_internal(data, frame, len, 8, 1);
+ return sbc_pack_frame_internal(
+ data, frame, len, 8, 1, joint);
else
- return sbc_pack_frame_internal(data, frame, len, 8, 2);
+ return sbc_pack_frame_internal(
+ data, frame, len, 8, 2, joint);
}
}
@@ -1055,10 +1018,11 @@
}
ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
- void *output, size_t output_len, size_t *written)
+ void *output, size_t output_len, ssize_t *written)
{
struct sbc_priv *priv;
- int framelen, samples;
+ int samples;
+ ssize_t framelen;
int (*sbc_enc_process_input)(int position,
const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
int nsamples, int nchannels);
@@ -1120,11 +1084,18 @@
samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
- priv->enc_state.sbc_calc_scalefactors(
- priv->frame.sb_sample_f, priv->frame.scale_factor,
- priv->frame.blocks, priv->frame.channels, priv->frame.subbands);
-
- framelen = sbc_pack_frame(output, &priv->frame, output_len);
+ if (priv->frame.mode == JOINT_STEREO) {
+ int j = priv->enc_state.sbc_calc_scalefactors_j(
+ priv->frame.sb_sample_f, priv->frame.scale_factor,
+ priv->frame.blocks, priv->frame.subbands);
+ framelen = sbc_pack_frame(output, &priv->frame, output_len, j);
+ } else {
+ priv->enc_state.sbc_calc_scalefactors(
+ priv->frame.sb_sample_f, priv->frame.scale_factor,
+ priv->frame.blocks, priv->frame.channels,
+ priv->frame.subbands);
+ framelen = sbc_pack_frame(output, &priv->frame, output_len, 0);
+ }
if (written)
*written = framelen;
@@ -1137,8 +1108,7 @@
if (!sbc)
return;
- if (sbc->priv_alloc_base)
- free(sbc->priv_alloc_base);
+ free(sbc->priv_alloc_base);
memset(sbc, 0, sizeof(sbc_t));
}
diff --git a/sbc/sbc.h b/sbc/sbc.h
index 0d834d6..2f830ad 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
@@ -91,7 +92,7 @@
/* Encodes ONE input block into ONE output block */
ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
- void *output, size_t output_len, size_t *written);
+ void *output, size_t output_len, ssize_t *written);
/* Returns the output block size in bytes */
size_t sbc_get_frame_length(sbc_t *sbc);
diff --git a/sbc/sbc_math.h b/sbc/sbc_math.h
index b87bc81..9f126c6 100644
--- a/sbc/sbc_math.h
+++ b/sbc/sbc_math.h
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index 2105280..f87fb5a 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
@@ -33,6 +34,7 @@
#include "sbc_primitives.h"
#include "sbc_primitives_mmx.h"
#include "sbc_primitives_neon.h"
+#include "sbc_primitives_armv6.h"
/*
* A reference C code of analysis filter with SIMD-friendly tables
@@ -439,6 +441,80 @@
}
}
+static int sbc_calc_scalefactors_j(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands)
+{
+ int blk, joint = 0;
+ int32_t tmp0, tmp1;
+ uint32_t x, y;
+
+ /* last subband does not use joint stereo */
+ int sb = subbands - 1;
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = fabs(sb_sample_f[blk][0][sb]);
+ tmp1 = fabs(sb_sample_f[blk][1][sb]);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+ scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+ /* the rest of subbands can use joint stereo */
+ while (--sb >= 0) {
+ int32_t sb_sample_j[16][2];
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = sb_sample_f[blk][0][sb];
+ tmp1 = sb_sample_f[blk][1][sb];
+ sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1);
+ sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1);
+ tmp0 = fabs(tmp0);
+ tmp1 = fabs(tmp1);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ scale_factor[0][sb] = (31 - SCALE_OUT_BITS) -
+ sbc_clz(x);
+ scale_factor[1][sb] = (31 - SCALE_OUT_BITS) -
+ sbc_clz(y);
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = fabs(sb_sample_j[blk][0]);
+ tmp1 = fabs(sb_sample_j[blk][1]);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ x = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+ y = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+ /* decide whether to use joint stereo for this subband */
+ if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) {
+ joint |= 1 << (subbands - 1 - sb);
+ scale_factor[0][sb] = x;
+ scale_factor[1][sb] = y;
+ for (blk = 0; blk < blocks; blk++) {
+ sb_sample_f[blk][0][sb] = sb_sample_j[blk][0];
+ sb_sample_f[blk][1][sb] = sb_sample_j[blk][1];
+ }
+ }
+ }
+
+ /* bitmask with the information about subbands using joint stereo */
+ return joint;
+}
+
/*
* Detect CPU features and setup function pointers
*/
@@ -456,6 +532,7 @@
/* Default implementation for scale factors calculation */
state->sbc_calc_scalefactors = sbc_calc_scalefactors;
+ state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j;
state->implementation_info = "Generic C";
/* X86/AMD64 optimizations */
@@ -464,6 +541,9 @@
#endif
/* ARM optimizations */
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+ sbc_init_primitives_armv6(state);
+#endif
#ifdef SBC_BUILD_WITH_NEON_SUPPORT
sbc_init_primitives_neon(state);
#endif
diff --git a/sbc/sbc_primitives.h b/sbc/sbc_primitives.h
index 3d01c11..3fec8d5 100644
--- a/sbc/sbc_primitives.h
+++ b/sbc/sbc_primitives.h
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
@@ -62,6 +63,10 @@
void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
uint32_t scale_factor[2][8],
int blocks, int channels, int subbands);
+ /* Scale factors calculation with joint stereo support */
+ int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands);
const char *implementation_info;
};
diff --git a/sbc/sbc_primitives_armv6.c b/sbc/sbc_primitives_armv6.c
new file mode 100644
index 0000000..9586098
--- /dev/null
+++ b/sbc/sbc_primitives_armv6.c
@@ -0,0 +1,299 @@
+/*
+ *
+ * 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
new file mode 100644
index 0000000..1862aed
--- /dev/null
+++ b/sbc/sbc_primitives_armv6.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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(__thumb__) && \
+ !defined(__ARM_NEON__)
+
+#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_mmx.c b/sbc/sbc_primitives_mmx.c
index 08e9ca2..45c62ac 100644
--- a/sbc/sbc_primitives_mmx.c
+++ b/sbc/sbc_primitives_mmx.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
@@ -275,6 +276,59 @@
asm volatile ("emms\n");
}
+static void sbc_calc_scalefactors_mmx(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands)
+{
+ static const SBC_ALIGNED int32_t consts[2] = {
+ 1 << SCALE_OUT_BITS,
+ 1 << SCALE_OUT_BITS,
+ };
+ int ch, sb;
+ intptr_t blk;
+ for (ch = 0; ch < channels; ch++) {
+ for (sb = 0; sb < subbands; sb += 2) {
+ blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]));
+ asm volatile (
+ "movq (%4), %%mm0\n"
+ "1:\n"
+ "movq (%1, %0), %%mm1\n"
+ "pxor %%mm2, %%mm2\n"
+ "pcmpgtd %%mm2, %%mm1\n"
+ "paddd (%1, %0), %%mm1\n"
+ "pcmpgtd %%mm1, %%mm2\n"
+ "pxor %%mm2, %%mm1\n"
+
+ "por %%mm1, %%mm0\n"
+
+ "sub %2, %0\n"
+ "jns 1b\n"
+
+ "movd %%mm0, %k0\n"
+ "psrlq $32, %%mm0\n"
+ "bsrl %k0, %k0\n"
+ "subl %5, %k0\n"
+ "movl %k0, (%3)\n"
+
+ "movd %%mm0, %k0\n"
+ "bsrl %k0, %k0\n"
+ "subl %5, %k0\n"
+ "movl %k0, 4(%3)\n"
+ : "+r" (blk)
+ : "r" (&sb_sample_f[0][ch][sb]),
+ "i" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ "r" (&scale_factor[ch][sb]),
+ "r" (&consts),
+ "i" (SCALE_OUT_BITS)
+ : "memory");
+ }
+ }
+ asm volatile ("emms\n");
+}
+
static int check_mmx_support(void)
{
#ifdef __amd64__
@@ -313,6 +367,7 @@
if (check_mmx_support()) {
state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_mmx;
state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_mmx;
+ state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx;
state->implementation_info = "MMX";
}
}
diff --git a/sbc/sbc_primitives_mmx.h b/sbc/sbc_primitives_mmx.h
index c1e44a5..e0e728b 100644
--- a/sbc/sbc_primitives_mmx.h
+++ b/sbc/sbc_primitives_mmx.h
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
diff --git a/sbc/sbc_primitives_neon.c b/sbc/sbc_primitives_neon.c
index f1bc7b4..0572158 100644
--- a/sbc/sbc_primitives_neon.c
+++ b/sbc/sbc_primitives_neon.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
@@ -236,10 +237,656 @@
_sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even);
}
+static void sbc_calc_scalefactors_neon(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands)
+{
+ int ch, sb;
+ for (ch = 0; ch < channels; ch++) {
+ for (sb = 0; sb < subbands; sb += 4) {
+ int blk = blocks;
+ int32_t *in = &sb_sample_f[0][ch][sb];
+ asm volatile (
+ "vmov.s32 q0, #0\n"
+ "vmov.s32 q1, %[c1]\n"
+ "vmov.s32 q14, #1\n"
+ "vmov.s32 q15, %[c2]\n"
+ "vadd.s32 q1, q1, q14\n"
+ "1:\n"
+ "vld1.32 {d16, d17}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q8, q8\n"
+ "vld1.32 {d18, d19}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q9, q9\n"
+ "vld1.32 {d20, d21}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q10, q10\n"
+ "vld1.32 {d22, d23}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q11, q11\n"
+ "vmax.s32 q0, q0, q8\n"
+ "vmax.s32 q1, q1, q9\n"
+ "vmax.s32 q0, q0, q10\n"
+ "vmax.s32 q1, q1, q11\n"
+ "subs %[blk], %[blk], #4\n"
+ "bgt 1b\n"
+ "vmax.s32 q0, q0, q1\n"
+ "vsub.s32 q0, q0, q14\n"
+ "vclz.s32 q0, q0\n"
+ "vsub.s32 q0, q15, q0\n"
+ "vst1.32 {d0, d1}, [%[out], :128]\n"
+ :
+ [blk] "+r" (blk),
+ [in] "+r" (in)
+ :
+ [inc] "r" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ [out] "r" (&scale_factor[ch][sb]),
+ [c1] "i" (1 << SCALE_OUT_BITS),
+ [c2] "i" (31 - SCALE_OUT_BITS)
+ : "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23", "d24", "d25", "d26",
+ "d27", "d28", "d29", "d30", "d31", "cc", "memory");
+ }
+ }
+}
+
+int sbc_calc_scalefactors_j_neon(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands)
+{
+ static SBC_ALIGNED int32_t joint_bits_mask[8] = {
+ 8, 4, 2, 1, 128, 64, 32, 16
+ };
+ int joint, i;
+ int32_t *in0, *in1;
+ int32_t *in = &sb_sample_f[0][0][0];
+ uint32_t *out0, *out1;
+ uint32_t *out = &scale_factor[0][0];
+ int32_t *consts = joint_bits_mask;
+
+ i = subbands;
+
+ asm volatile (
+ /*
+ * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
+ * input: q0 = ((1 << SCALE_OUT_BITS) + 1)
+ * %[in0] - samples for channel 0
+ * %[in1] - samples for shannel 1
+ * output: q0, q1 - scale factors without joint stereo
+ * q2, q3 - scale factors with joint stereo
+ * q15 - joint stereo selection mask
+ */
+ ".macro calc_scalefactors\n"
+ "vmov.s32 q1, q0\n"
+ "vmov.s32 q2, q0\n"
+ "vmov.s32 q3, q0\n"
+ "mov %[i], %[blocks]\n"
+ "1:\n"
+ "vld1.32 {d18, d19}, [%[in1], :128], %[inc]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d16, d17}, [%[in0], :128], %[inc]\n"
+ "vhadd.s32 q10, q8, q11\n"
+ "vhsub.s32 q11, q8, q11\n"
+ "vabs.s32 q8, q8\n"
+ "vabs.s32 q9, q9\n"
+ "vabs.s32 q10, q10\n"
+ "vabs.s32 q11, q11\n"
+ "vmax.s32 q0, q0, q8\n"
+ "vmax.s32 q1, q1, q9\n"
+ "vmax.s32 q2, q2, q10\n"
+ "vmax.s32 q3, q3, q11\n"
+ "subs %[i], %[i], #1\n"
+ "bgt 1b\n"
+ "vsub.s32 q0, q0, q14\n"
+ "vsub.s32 q1, q1, q14\n"
+ "vsub.s32 q2, q2, q14\n"
+ "vsub.s32 q3, q3, q14\n"
+ "vclz.s32 q0, q0\n"
+ "vclz.s32 q1, q1\n"
+ "vclz.s32 q2, q2\n"
+ "vclz.s32 q3, q3\n"
+ "vsub.s32 q0, q13, q0\n"
+ "vsub.s32 q1, q13, q1\n"
+ "vsub.s32 q2, q13, q2\n"
+ "vsub.s32 q3, q13, q3\n"
+ ".endm\n"
+ /*
+ * constants: q14 = 1
+ * input: q15 - joint stereo selection mask
+ * %[in0] - value set by calc_scalefactors macro
+ * %[in1] - value set by calc_scalefactors macro
+ */
+ ".macro update_joint_stereo_samples\n"
+ "sub %[out1], %[in1], %[inc]\n"
+ "sub %[out0], %[in0], %[inc]\n"
+ "sub %[in1], %[in1], %[inc], asl #1\n"
+ "sub %[in0], %[in0], %[inc], asl #1\n"
+ "vld1.32 {d18, d19}, [%[in1], :128]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d16, d17}, [%[in0], :128]\n"
+ "vld1.32 {d2, d3}, [%[out1], :128]\n"
+ "vbic.s32 q3, q1, q14\n"
+ "vld1.32 {d0, d1}, [%[out0], :128]\n"
+ "vhsub.s32 q10, q8, q11\n"
+ "vhadd.s32 q11, q8, q11\n"
+ "vhsub.s32 q2, q0, q3\n"
+ "vhadd.s32 q3, q0, q3\n"
+ "vbif.s32 q10, q9, q15\n"
+ "vbif.s32 d22, d16, d30\n"
+ "sub %[inc], %[zero], %[inc], asl #1\n"
+ "sub %[i], %[blocks], #2\n"
+ "2:\n"
+ "vbif.s32 d23, d17, d31\n"
+ "vst1.32 {d20, d21}, [%[in1], :128], %[inc]\n"
+ "vbif.s32 d4, d2, d30\n"
+ "vld1.32 {d18, d19}, [%[in1], :128]\n"
+ "vbif.s32 d5, d3, d31\n"
+ "vst1.32 {d22, d23}, [%[in0], :128], %[inc]\n"
+ "vbif.s32 d6, d0, d30\n"
+ "vld1.32 {d16, d17}, [%[in0], :128]\n"
+ "vbif.s32 d7, d1, d31\n"
+ "vst1.32 {d4, d5}, [%[out1], :128], %[inc]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d2, d3}, [%[out1], :128]\n"
+ "vst1.32 {d6, d7}, [%[out0], :128], %[inc]\n"
+ "vbic.s32 q3, q1, q14\n"
+ "vld1.32 {d0, d1}, [%[out0], :128]\n"
+ "vhsub.s32 q10, q8, q11\n"
+ "vhadd.s32 q11, q8, q11\n"
+ "vhsub.s32 q2, q0, q3\n"
+ "vhadd.s32 q3, q0, q3\n"
+ "vbif.s32 q10, q9, q15\n"
+ "vbif.s32 d22, d16, d30\n"
+ "subs %[i], %[i], #2\n"
+ "bgt 2b\n"
+ "sub %[inc], %[zero], %[inc], asr #1\n"
+ "vbif.s32 d23, d17, d31\n"
+ "vst1.32 {d20, d21}, [%[in1], :128]\n"
+ "vbif.s32 q2, q1, q15\n"
+ "vst1.32 {d22, d23}, [%[in0], :128]\n"
+ "vbif.s32 q3, q0, q15\n"
+ "vst1.32 {d4, d5}, [%[out1], :128]\n"
+ "vst1.32 {d6, d7}, [%[out0], :128]\n"
+ ".endm\n"
+
+ "vmov.s32 q14, #1\n"
+ "vmov.s32 q13, %[c2]\n"
+
+ "cmp %[i], #4\n"
+ "bne 8f\n"
+
+ "4:\n" /* 4 subbands */
+ "add %[in0], %[in], #0\n"
+ "add %[in1], %[in], #32\n"
+ "add %[out0], %[out], #0\n"
+ "add %[out1], %[out], #32\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 0, 1, 2 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* calculate and save to memory 'joint' variable */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ " vpadd.s32 d16, d16, d16\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vst1.32 {d16[0]}, [%[joint]]\n"
+
+ "update_joint_stereo_samples\n"
+ "b 9f\n"
+
+ "8:\n" /* 8 subbands */
+ "add %[in0], %[in], #16\n\n"
+ "add %[in1], %[in], #48\n"
+ "add %[out0], %[out], #16\n\n"
+ "add %[out1], %[out], #48\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 4, 5, 6 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* calculate part of 'joint' variable and save it to d24 */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vpadd.s32 d24, d16, d16\n"
+
+ "update_joint_stereo_samples\n"
+
+ "add %[in0], %[in], #0\n"
+ "add %[in1], %[in], #32\n"
+ "add %[out0], %[out], #0\n\n"
+ "add %[out1], %[out], #32\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 0, 1, 2, 3 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* combine last part of 'joint' with d24 and save to memory */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ " vpadd.s32 d16, d16, d16\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ " vadd.s32 d16, d16, d24\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vst1.32 {d16[0]}, [%[joint]]\n"
+
+ "update_joint_stereo_samples\n"
+ "9:\n"
+ ".purgem calc_scalefactors\n"
+ ".purgem update_joint_stereo_samples\n"
+ :
+ [i] "+&r" (i),
+ [in] "+&r" (in),
+ [in0] "=&r" (in0),
+ [in1] "=&r" (in1),
+ [out] "+&r" (out),
+ [out0] "=&r" (out0),
+ [out1] "=&r" (out1),
+ [consts] "+&r" (consts)
+ :
+ [inc] "r" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ [blocks] "r" (blocks),
+ [joint] "r" (&joint),
+ [c1] "i" (1 << SCALE_OUT_BITS),
+ [c2] "i" (31 - SCALE_OUT_BITS),
+ [zero] "r" (0)
+ : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d16", "d17", "d18", "d19", "d20", "d21", "d22",
+ "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+ "d30", "d31", "cc", "memory");
+
+ return joint;
+}
+
+#define PERM_BE(a, b, c, d) { \
+ (a * 2) + 1, (a * 2) + 0, \
+ (b * 2) + 1, (b * 2) + 0, \
+ (c * 2) + 1, (c * 2) + 0, \
+ (d * 2) + 1, (d * 2) + 0 \
+ }
+#define PERM_LE(a, b, c, d) { \
+ (a * 2) + 0, (a * 2) + 1, \
+ (b * 2) + 0, (b * 2) + 1, \
+ (c * 2) + 0, (c * 2) + 1, \
+ (d * 2) + 0, (d * 2) + 1 \
+ }
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ static SBC_ALIGNED uint8_t perm_be[2][8] = {
+ PERM_BE(7, 3, 6, 4),
+ PERM_BE(0, 2, 1, 5)
+ };
+ static SBC_ALIGNED uint8_t perm_le[2][8] = {
+ PERM_LE(7, 3, 6, 4),
+ PERM_LE(0, 2, 1, 5)
+ };
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
+ int16_t *src = &X[0][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0}, [%[src], :64]!\n"
+ "vst1.16 {d0}, [%[dst], :64]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ if (nchannels > 1) {
+ dst = &X[1][SBC_X_BUFFER_SIZE - 40];
+ src = &X[1][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0}, [%[src], :64]!\n"
+ "vst1.16 {d0}, [%[dst], :64]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ }
+ position = SBC_X_BUFFER_SIZE - 40;
+ }
+
+ if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+ /* poor 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[y], %[y], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld1.8 {d4, d5}, [%[pcm]]!\n"
+ "vuzp.16 d4, d5\n"
+ "vld1.8 {d20, d21}, [%[pcm]]!\n"
+ "vuzp.16 d20, d21\n"
+ "vswp d5, d20\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vtbl.8 d18, {d20, d21}, d0\n"
+ "vtbl.8 d19, {d20, d21}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "vst1.16 {d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else if (nchannels > 1) {
+ /* proper 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[y], %[y], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld2.16 {d4, d5}, [%[pcm]]!\n"
+ "vld2.16 {d20, d21}, [%[pcm]]!\n"
+ "vswp d5, d20\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vtbl.8 d18, {d20, d21}, d0\n"
+ "vtbl.8 d19, {d20, d21}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "vst1.16 {d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else {
+ int16_t *x = &X[0][position];
+ asm volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld1.8 {d4, d5}, [%[pcm]]!\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+ }
+ return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ static SBC_ALIGNED uint8_t perm_be[4][8] = {
+ PERM_BE(15, 7, 14, 8),
+ PERM_BE(13, 9, 12, 10),
+ PERM_BE(11, 3, 6, 0),
+ PERM_BE(5, 1, 4, 2)
+ };
+ static SBC_ALIGNED uint8_t perm_le[4][8] = {
+ PERM_LE(15, 7, 14, 8),
+ PERM_LE(13, 9, 12, 10),
+ PERM_LE(11, 3, 6, 0),
+ PERM_LE(5, 1, 4, 2)
+ };
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
+ int16_t *src = &X[0][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1}, [%[dst], :128]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ if (nchannels > 1) {
+ dst = &X[1][SBC_X_BUFFER_SIZE - 72];
+ src = &X[1][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1}, [%[dst], :128]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ }
+ position = SBC_X_BUFFER_SIZE - 72;
+ }
+
+ if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+ /* poor 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[y], %[y], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vuzp.16 q2, q3\n"
+ "vld1.8 {d20, d21, d22, d23}, [%[pcm]]!\n"
+ "vuzp.16 q10, q11\n"
+ "vswp q3, q10\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "vtbl.8 d16, {d20, d21, d22, d23}, d0\n"
+ "vtbl.8 d17, {d20, d21, d22, d23}, d1\n"
+ "vtbl.8 d18, {d20, d21, d22, d23}, d2\n"
+ "vtbl.8 d19, {d20, d21, d22, d23}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else if (nchannels > 1) {
+ /* proper 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[y], %[y], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld2.16 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vld2.16 {d20, d21, d22, d23}, [%[pcm]]!\n"
+ "vswp q3, q10\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "vtbl.8 d16, {d20, d21, d22, d23}, d0\n"
+ "vtbl.8 d17, {d20, d21, d22, d23}, d1\n"
+ "vtbl.8 d18, {d20, d21, d22, d23}, d2\n"
+ "vtbl.8 d19, {d20, d21, d22, d23}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else {
+ int16_t *x = &X[0][position];
+ asm volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+ }
+ return position;
+}
+
+#undef PERM_BE
+#undef PERM_LE
+
+static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_4s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_4s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 0);
+}
+
+static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_8s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_8s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 0);
+}
+
void sbc_init_primitives_neon(struct sbc_encoder_state *state)
{
state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon;
state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon;
+ state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
+ state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
+ state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon;
+ state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon;
+ state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon;
+ state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon;
state->implementation_info = "NEON";
}
diff --git a/sbc/sbc_primitives_neon.h b/sbc/sbc_primitives_neon.h
index 30766ed..ea3da06 100644
--- a/sbc/sbc_primitives_neon.h
+++ b/sbc/sbc_primitives_neon.h
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
diff --git a/sbc/sbc_tables.h b/sbc/sbc_tables.h
index 0057c73..28c0d54 100644
--- a/sbc/sbc_tables.h
+++ b/sbc/sbc_tables.h
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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>
*
diff --git a/sbc/sbcdec.c b/sbc/sbcdec.c
index 9e87d63..7008e88 100644
--- a/sbc/sbcdec.c
+++ b/sbc/sbcdec.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) decoder
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -219,7 +220,7 @@
static void usage(void)
{
printf("SBC decoder utility ver %s\n", VERSION);
- printf("Copyright (c) 2004-2009 Marcel Holtmann\n\n");
+ printf("Copyright (c) 2004-2010 Marcel Holtmann\n\n");
printf("Usage:\n"
"\tsbcdec [options] file(s)\n"
@@ -258,15 +259,13 @@
break;
case 'd':
- if (output)
- free(output);
+ free(output);
output = strdup(optarg);
tofile = 0;
break;
case 'f' :
- if (output)
- free(output);
+ free(output);
output = strdup(optarg);
tofile = 1;
break;
@@ -288,8 +287,7 @@
for (i = 0; i < argc; i++)
decode(argv[i], output ? output : "/dev/dsp", tofile);
- if (output)
- free(output);
+ free(output);
return 0;
}
diff --git a/sbc/sbcenc.c b/sbc/sbcenc.c
index 0e3b6fb..3d3a7dc 100644
--- a/sbc/sbcenc.c
+++ b/sbc/sbcenc.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) encoder
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -49,7 +50,7 @@
struct au_header au_hdr;
sbc_t sbc;
int fd, size, srate, codesize, nframes;
- size_t encoded;
+ ssize_t encoded;
ssize_t len;
if (sizeof(au_hdr) != 24) {
@@ -205,7 +206,7 @@
static void usage(void)
{
printf("SBC encoder utility ver %s\n", VERSION);
- printf("Copyright (c) 2004-2009 Marcel Holtmann\n\n");
+ printf("Copyright (c) 2004-2010 Marcel Holtmann\n\n");
printf("Usage:\n"
"\tsbcenc [options] file(s)\n"
diff --git a/sbc/sbcinfo.c b/sbc/sbcinfo.c
index 645de9b..6d92679 100644
--- a/sbc/sbcinfo.c
+++ b/sbc/sbcinfo.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/sbc/sbctester.c b/sbc/sbctester.c
index a7cf85f..b1e3608 100644
--- a/sbc/sbctester.c
+++ b/sbc/sbctester.c
@@ -2,7 +2,8 @@
*
* Bluetooth low-complexity, subband codec (SBC) library
*
- * Copyright (C) 2007-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2007-2008 Frederic Dalleau <fdalleau@free.fr>
*
*
@@ -247,7 +248,7 @@
static void usage()
{
printf("SBC conformance test ver %s\n", VERSION);
- printf("Copyright (c) 2007-2009 Marcel Holtmann\n");
+ printf("Copyright (c) 2007-2010 Marcel Holtmann\n");
printf("Copyright (c) 2007-2008 Frederic Dalleau\n\n");
printf("Usage:\n"
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
deleted file mode 100644
index cbd30b1..0000000
--- a/scripts/Makefile.am
+++ /dev/null
@@ -1,35 +0,0 @@
-
-if UDEVRULES
-rulesdir = @UDEV_DATADIR@
-
-rules_DATA = 97-bluetooth.rules
-
-if HID2HCI
-rules_DATA += 97-bluetooth-hid2hci.rules
-endif
-
-if PCMCIA
-rules_DATA += 97-bluetooth-serial.rules
-endif
-endif
-
-if PCMCIA
-udevdir = $(libexecdir)/udev
-
-udev_SCRIPTS = bluetooth_serial
-endif
-
-CLEANFILES = $(rules_DATA)
-
-EXTRA_DIST = bluetooth-hid2hci.rules bluetooth-serial.rules bluetooth_serial
-
-MAINTAINERCLEANFILES = Makefile.in
-
-97-bluetooth.rules: bluetooth.rules
- cp $< $@
-
-97-bluetooth-hid2hci.rules: bluetooth-hid2hci.rules
- cp $< $@
-
-97-bluetooth-serial.rules: bluetooth-serial.rules
- cp $< $@
diff --git a/serial/Makefile.am b/serial/Makefile.am
deleted file mode 100644
index f8f26e2..0000000
--- a/serial/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-
-if SERIALPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = serial.la
-
-serial_la_SOURCES = main.c \
- manager.h manager.c port.h port.c \
- proxy.h proxy.c
-
-LDADD = $(top_builddir)/common/libhelper.a \
- @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden \
- @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = serial.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/serial/main.c b/serial/main.c
index 71e5aa3..38ded03 100644
--- a/serial/main.c
+++ b/serial/main.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/serial/manager.c b/serial/manager.c
index 71f1a5e..1b3f1d6 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -55,7 +55,7 @@
#include "adapter.h"
#include "device.h"
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "error.h"
@@ -66,14 +66,9 @@
#include "sdpd.h"
#include "glib-helper.h"
-#define SERIAL_PORT_UUID "00001101-0000-1000-8000-00805F9B34FB"
-#define DIALUP_NET_UUID "00001103-0000-1000-8000-00805F9B34FB"
-#define OBJECT_PUSH_UUID "00001105-0000-1000-8000-00805F9B34FB"
-#define FILE_TRANSFER_UUID "00001106-0000-1000-8000-00805F9B34FB"
#define RFCOMM_UUID_STR "00000003-0000-1000-8000-00805F9B34FB"
static DBusConnection *connection = NULL;
-GSList *adapters = NULL;
static int serial_probe(struct btd_device *device, const char *uuid)
{
diff --git a/serial/manager.h b/serial/manager.h
index 112cf2f..c8b96e8 100644
--- a/serial/manager.h
+++ b/serial/manager.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/serial/port.c b/serial/port.c
index 42a4f3d..48a60b4 100644
--- a/serial/port.c
+++ b/serial/port.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@
#include "../src/dbus-common.h"
-#include "logging.h"
+#include "log.h"
#include "glib-helper.h"
#include "btio.h"
@@ -155,7 +155,7 @@
return 0;
}
- debug("Serial port %s released", port->dev);
+ DBG("Serial port %s released", port->dev);
rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
if (rfcomm_ctl < 0)
@@ -223,7 +223,7 @@
{
struct serial_device *device = data;
- debug("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
+ DBG("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
device->path);
devices = g_slist_remove(devices, device);
@@ -358,7 +358,7 @@
port->dev = g_strdup_printf("/dev/rfcomm%d", port->id);
- debug("Serial port %s created", port->dev);
+ DBG("Serial port %s created", port->dev);
g_io_channel_shutdown(chan, TRUE, NULL);
@@ -592,7 +592,7 @@
return NULL;
}
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
SERIAL_PORT_INTERFACE, path);
return device;
diff --git a/serial/port.h b/serial/port.h
index 6b638cb..74ac9f0 100644
--- a/serial/port.h
+++ b/serial/port.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/serial/proxy.c b/serial/proxy.c
index 88a414d..6577fe2 100644
--- a/serial/proxy.c
+++ b/serial/proxy.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -54,7 +54,7 @@
#include "../src/dbus-common.h"
#include "../src/adapter.h"
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "error.h"
@@ -63,12 +63,6 @@
#include "btio.h"
#include "proxy.h"
-#define SERIAL_PORT_NAME "spp"
-#define SERIAL_PORT_UUID "00001101-0000-1000-8000-00805F9B34FB"
-
-#define DIALUP_NET_NAME "dun"
-#define DIALUP_NET_UUID "00001103-0000-1000-8000-00805F9B34FB"
-
#define SERIAL_PROXY_INTERFACE "org.bluez.SerialProxy"
#define SERIAL_MANAGER_INTERFACE "org.bluez.SerialProxyManager"
#define BUF_SIZE 1024
@@ -493,7 +487,7 @@
goto drop;
}
- debug("Serial Proxy: incoming connect from %s", address);
+ DBG("Serial Proxy: incoming connect from %s", address);
prx->rfcomm = g_io_channel_ref(chan);
@@ -539,7 +533,7 @@
goto failed;
}
- debug("Allocated channel %d", prx->channel);
+ DBG("Allocated channel %d", prx->channel);
g_io_channel_set_close_on_unref(prx->io, TRUE);
@@ -794,7 +788,7 @@
struct serial_proxy *prx = data;
int sk;
- debug("Unregistered proxy: %s", prx->address);
+ DBG("Unregistered proxy: %s", prx->address);
if (prx->type != TTY_PROXY)
goto done;
@@ -829,7 +823,7 @@
prx->path = g_strdup(path);
adapter->proxies = g_slist_append(adapter->proxies, prx);
- debug("Registered proxy: %s", path);
+ DBG("Registered proxy: %s", path);
return 0;
}
@@ -1225,19 +1219,21 @@
uuid_str = g_key_file_get_string(config, group_str, "UUID",
&gerr);
if (gerr) {
- debug("%s: %s", file, gerr->message);
+ 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) {
- debug("%s: %s", file, gerr->message);
+ DBG("%s: %s", file, gerr->message);
g_error_free(gerr);
g_key_file_free(config);
g_free(uuid_str);
+ g_strfreev(group_list);
return;
}
@@ -1245,7 +1241,7 @@
if (err == -EINVAL)
error("Invalid address.");
else if (err == -EALREADY)
- debug("Proxy already exists.");
+ DBG("Proxy already exists.");
else if (err < 0)
error("Proxy creation failed (%s)", strerror(-err));
else {
@@ -1289,7 +1285,7 @@
adapters = g_slist_append(adapters, adapter);
- debug("Registered interface %s on path %s",
+ DBG("Registered interface %s on path %s",
SERIAL_MANAGER_INTERFACE, path);
serial_proxy_init(adapter);
diff --git a/serial/proxy.h b/serial/proxy.h
index 721e97d..7871665 100644
--- a/serial/proxy.h
+++ b/serial/proxy.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Android.mk b/src/Android.mk
index 504a272..7030d79 100755
--- a/src/Android.mk
+++ b/src/Android.mk
@@ -7,25 +7,32 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ android_bluez.c \
adapter.c \
agent.c \
+ btio.c \
dbus-common.c \
dbus-hci.c \
device.c \
error.c \
+ glib-helper.c \
+ log.c \
main.c \
manager.c \
+ oui.c \
plugin.c \
rfkill.c \
sdpd-request.c \
sdpd-service.c \
sdpd-server.c \
sdpd-database.c \
+ sdp-xml.c \
security.c \
- storage.c
+ storage.c \
+ textfile.c
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" \
+ -DVERSION=\"4.69\" \
-DSTORAGEDIR=\"/data/misc/bluetoothd\" \
-DCONFIGDIR=\"/etc/bluetooth\" \
-DSERVICEDIR=\"/system/bin\" \
@@ -34,8 +41,7 @@
-DANDROID_EXPAND_NAME
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
$(LOCAL_PATH)/../gdbus \
$(LOCAL_PATH)/../plugins \
$(call include-path-for, glib) \
@@ -50,7 +56,6 @@
LOCAL_STATIC_LIBRARIES := \
libglib_static \
- libbluez-common-static \
libbuiltinplugin \
libgdbus_static
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index 569c060..0000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,47 +0,0 @@
-
-if CONFIGFILES
-dbusdir = $(sysconfdir)/dbus-1/system.d
-
-dbus_DATA = bluetooth.conf
-
-confdir = $(sysconfdir)/bluetooth
-
-conf_DATA = main.conf
-
-statedir = $(localstatedir)/lib/bluetooth
-
-state_DATA =
-endif
-
-sbin_PROGRAMS = bluetoothd
-
-bluetoothd_SOURCES = main.c security.c hcid.h sdpd.h \
- sdpd-server.c sdpd-request.c sdpd-service.c sdpd-database.c \
- plugin.h plugin.c storage.h storage.c agent.h agent.c rfkill.c \
- error.h error.c manager.h manager.c adapter.h adapter.c \
- device.h device.c dbus-common.c dbus-common.h dbus-hci.h dbus-hci.c
-
-bluetoothd_LDADD = $(top_builddir)/common/libhelper.a \
- $(top_builddir)/plugins/libbuiltin.la \
- @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ -ldl
-
-bluetoothd_LDFLAGS = -Wl,--export-dynamic
-
-if MAINTAINER_MODE
-plugindir = $(abs_top_srcdir)/plugins
-else
-plugindir = $(libdir)/bluetooth/plugins
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ \
- -DPLUGINDIR=\""$(plugindir)"\"
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_builddir)/plugins
-
-if MANPAGES
-man_MANS = bluetoothd.8
-endif
-
-EXTRA_DIST = bluetooth.conf bluetoothd.8 main.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/adapter.c b/src/adapter.c
index bb2f320..c6dbd05 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -29,7 +29,6 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
-#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
@@ -37,7 +36,6 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
@@ -45,12 +43,11 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "hcid.h"
#include "sdpd.h"
-#include "sdp-xml.h"
#include "manager.h"
#include "adapter.h"
#include "device.h"
@@ -61,14 +58,15 @@
#include "agent.h"
#include "storage.h"
-#define NUM_ELEMENTS(table) (sizeof(table)/sizeof(const char *))
-
#define IO_CAPABILITY_DISPLAYONLY 0x00
#define IO_CAPABILITY_DISPLAYYESNO 0x01
#define IO_CAPABILITY_KEYBOARDONLY 0x02
#define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03
#define IO_CAPABILITY_INVALID 0xFF
+/* Limited Discoverable bit mask in CoD */
+#define LIMITED_BIT 0x002000
+
#define check_address(address) bachk(address)
static DBusConnection *connection = NULL;
@@ -90,6 +88,7 @@
service_auth_cb cb;
void *user_data;
struct btd_device *device;
+ struct btd_adapter *adapter;
};
struct btd_adapter {
@@ -106,20 +105,22 @@
uint8_t mode; /* off, connectable, discoverable,
* limited */
uint8_t global_mode; /* last valid global mode */
+ struct session_req *pending_mode;
int state; /* standard inq, periodic inq, name
* resloving */
GSList *found_devices;
GSList *oor_devices; /* out of range device list */
- DBusMessage *discovery_cancel; /* discovery cancel message request */
- GSList *passkey_agents;
struct agent *agent; /* For the new API */
+ guint auth_idle_id; /* Ongoing authorization */
GSList *connections; /* Connected devices */
GSList *devices; /* Devices structure pointers */
GSList *mode_sessions; /* Request Mode sessions */
GSList *disc_sessions; /* Discovery sessions */
guint scheduler_id; /* Scheduler handle */
+ sdp_list_t *services; /* Services associated to adapter */
struct hci_dev dev; /* hci info */
+ int8_t tx_power; /* inq response tx power level */
gboolean pairable; /* pairable state */
gboolean initialized;
@@ -127,7 +128,10 @@
gboolean off_requested; /* DEVDOWN ioctl was called */
- uint8_t svc_cache; /* Service Class cache */
+ uint32_t current_cod; /* Adapter's current class */
+ uint32_t pending_cod;
+ uint32_t wanted_cod; /* CoD cache */
+
gboolean cache_enable;
gint ref;
@@ -142,35 +146,18 @@
"Invalid arguments in method call");
}
-static inline DBusMessage *not_available(DBusMessage *msg)
-{
- return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
- "Not Available");
-}
-
static inline DBusMessage *adapter_not_ready(DBusMessage *msg)
{
return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady",
"Adapter is not ready");
}
-static inline DBusMessage *no_such_adapter(DBusMessage *msg)
-{
- return g_dbus_create_error(msg, ERROR_INTERFACE ".NoSuchAdapter",
- "No such adapter");
-}
-
static inline DBusMessage *failed_strerror(DBusMessage *msg, int err)
{
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
strerror(err));
}
-static inline DBusMessage *in_progress(DBusMessage *msg, const char *str)
-{
- return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", str);
-}
-
static inline DBusMessage *not_in_progress(DBusMessage *msg, const char *str)
{
return g_dbus_create_error(msg, ERROR_INTERFACE ".NotInProgress", str);
@@ -182,13 +169,6 @@
"Not authorized");
}
-static inline DBusMessage *unsupported_major_class(DBusMessage *msg)
-{
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".UnsupportedMajorClass",
- "Unsupported Major Class");
-}
-
static int found_device_cmp(const struct remote_dev_info *d1,
const struct remote_dev_info *d2)
{
@@ -226,72 +206,58 @@
adapter->found_devices = NULL;
}
-static int set_service_classes(struct btd_adapter *adapter, uint8_t value)
+static int adapter_set_service_classes(struct btd_adapter *adapter,
+ uint8_t value)
{
- struct hci_dev *dev = &adapter->dev;
- const uint8_t *cls = dev->class;
- uint32_t dev_class;
- int dd, err;
+ int err;
- if (cls[2] == value)
- return 0; /* Already set */
+ /* Update only the service class, keep the limited bit,
+ * major/minor class bits intact */
+ adapter->wanted_cod &= 0x00ffff;
+ adapter->wanted_cod |= (value << 16);
- dd = hci_open_dev(adapter->dev_id);
- if (dd < 0) {
- err = -errno;
- error("Can't open device hci%d: %s (%d)",
- adapter->dev_id, strerror(errno), errno);
- return err;
- }
+ /* If we already have the CoD we want or the cache is enabled or an
+ * existing CoD write is in progress just bail out */
+ if (adapter->current_cod == adapter->wanted_cod ||
+ adapter->cache_enable || adapter->pending_cod)
+ return 0;
- dev_class = (value << 16) | (cls[1] << 8) | cls[0];
+ DBG("Changing service classes to 0x%06x", adapter->wanted_cod);
- debug("Changing service classes to 0x%06x", dev_class);
+ err = adapter_ops->set_class(adapter->dev_id, adapter->wanted_cod);
+ if (err < 0)
+ error("Adapter class update failed: %s(%d)",
+ strerror(err), err);
+ else
+ adapter->pending_cod = adapter->wanted_cod;
- if (hci_write_class_of_dev(dd, dev_class, HCI_REQ_TIMEOUT) < 0) {
- err = -errno;
- error("Can't write class of device: %s (%d)",
- strerror(errno), errno);
- hci_close_dev(dd);
- return err;
- }
-
- hci_close_dev(dd);
-
- return 0;
+ return err;
}
-int set_major_and_minor_class(struct btd_adapter *adapter, uint8_t major,
+int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
uint8_t minor)
{
- struct hci_dev *dev = &adapter->dev;
- const uint8_t *cls = dev->class;
- uint32_t dev_class;
- int dd, err;
+ int err;
- dd = hci_open_dev(adapter->dev_id);
- if (dd < 0) {
- err = -errno;
- error("Can't open device hci%d: %s (%d)",
- adapter->dev_id, strerror(errno), errno);
- return err;
- }
+ /* Update only the major and minor class bits keeping remaining bits
+ * intact*/
+ adapter->wanted_cod &= 0xffe000;
+ adapter->wanted_cod |= ((major & 0x1f) << 8) | minor;
- dev_class = (cls[2] << 16) | ((cls[1] & 0x20) << 8) |
- ((major & 0xdf) << 8) | minor;
+ if (adapter->wanted_cod == adapter->current_cod ||
+ adapter->cache_enable || adapter->pending_cod)
+ return 0;
- debug("Changing major/minor class to 0x%06x", dev_class);
+ DBG("Changing Major/Minor class to 0x%06x", adapter->wanted_cod);
- if (hci_write_class_of_dev(dd, dev_class, HCI_REQ_TIMEOUT) < 0) {
- int err = -errno;
- error("Can't write class of device: %s (%d)",
- strerror(errno), errno);
- hci_close_dev(dd);
- return err;
- }
+ err = adapter_ops->set_class(adapter->dev_id, adapter->wanted_cod);
+ if (err < 0)
+ error("Adapter class update failed: %s(%d)",
+ strerror(err), err);
+ else
+ adapter->pending_cod = adapter->wanted_cod;
- hci_close_dev(dd);
- return 0;
+ return err;
}
int pending_remote_name_cancel(struct btd_adapter *adapter)
@@ -428,10 +394,66 @@
adapter);
}
-static int set_mode(struct btd_adapter *adapter, uint8_t new_mode)
+static void adapter_set_limited_discoverable(struct btd_adapter *adapter,
+ gboolean limited)
+{
+ /* Check if limited bit needs to be set/reset */
+ if (limited)
+ adapter->wanted_cod |= LIMITED_BIT;
+ else
+ adapter->wanted_cod &= ~LIMITED_BIT;
+
+ /* If we dont need the toggling, save an unnecessary CoD write */
+ if (adapter->pending_cod ||
+ adapter->wanted_cod == adapter->current_cod)
+ return;
+
+ if (adapter_ops->set_limited_discoverable(adapter->dev_id,
+ adapter->wanted_cod, limited) == 0)
+ adapter->pending_cod = adapter->wanted_cod;
+}
+
+static struct session_req *session_ref(struct session_req *req)
+{
+ req->refcount++;
+
+ DBG("%p: ref=%d", req, req->refcount);
+
+ return req;
+}
+
+static struct session_req *create_session(struct btd_adapter *adapter,
+ DBusConnection *conn, DBusMessage *msg,
+ uint8_t mode, GDBusWatchFunction cb)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct session_req *req;
+
+ req = g_new0(struct session_req, 1);
+ req->adapter = adapter;
+ req->conn = dbus_connection_ref(conn);
+ req->msg = dbus_message_ref(msg);
+ req->mode = mode;
+
+ if (cb == NULL)
+ return session_ref(req);
+
+ req->owner = g_strdup(sender);
+ req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL);
+
+ info("%s session %p with %s activated",
+ req->mode ? "Mode" : "Discovery", req, sender);
+
+ return session_ref(req);
+}
+
+static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
+ DBusMessage *msg)
{
int err;
- const char *modestr;
+
+ if (adapter->pending_mode != NULL)
+ return -EALREADY;
if (!adapter->up && new_mode != MODE_OFF) {
err = adapter_ops->set_powered(adapter->dev_id, TRUE);
@@ -468,16 +490,22 @@
adapter->discov_timeout);
if (new_mode != MODE_LIMITED && adapter->mode == MODE_LIMITED)
- adapter_ops->set_limited_discoverable(adapter->dev_id,
- adapter->dev.class, FALSE);
+ adapter_set_limited_discoverable(adapter, FALSE);
}
done:
- modestr = mode2str(new_mode);
+ DBG("%s", mode2str(new_mode));
- write_device_mode(&adapter->bdaddr, modestr);
-
- adapter->mode = new_mode;
+ if (msg != NULL)
+ /* Wait for mode change to reply */
+ adapter->pending_mode = create_session(adapter, connection,
+ msg, new_mode, NULL);
+ else {
+ /* Nothing to reply just write the new mode */
+ const char *modestr = mode2str(new_mode);
+ adapter->mode = new_mode;
+ write_device_mode(&adapter->bdaddr, modestr);
+ }
return 0;
}
@@ -494,7 +522,7 @@
if (mode == adapter->mode)
return dbus_message_new_method_return(msg);
- err = set_mode(adapter, mode);
+ err = set_mode(adapter, mode, NULL);
if (err < 0)
return failed_strerror(msg, -err);
@@ -518,11 +546,11 @@
if (mode == adapter->mode)
return dbus_message_new_method_return(msg);
- err = set_mode(adapter, mode);
+ err = set_mode(adapter, mode, msg);
if (err < 0)
return failed_strerror(msg, -err);
- return dbus_message_new_method_return(msg);
+ return 0;
}
static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
@@ -538,6 +566,19 @@
if (pairable == adapter->pairable)
goto done;
+ if (!(adapter->scan_mode & SCAN_INQUIRY))
+ goto store;
+
+ mode = (pairable && adapter->discov_timeout > 0 &&
+ adapter->discov_timeout <= 60) ?
+ MODE_LIMITED : MODE_DISCOVERABLE;
+
+ err = set_mode(adapter, mode, NULL);
+ if (err < 0 && msg)
+ return failed_strerror(msg, -err);
+
+store:
+
adapter->pairable = pairable;
write_device_pairable(&adapter->bdaddr, pairable);
@@ -550,17 +591,6 @@
adapter_set_pairable_timeout(adapter,
adapter->pairable_timeout);
- if (!(adapter->scan_mode & SCAN_INQUIRY))
- goto done;
-
- mode = (pairable && adapter->discov_timeout > 0 &&
- adapter->discov_timeout <= 60) ?
- MODE_LIMITED : MODE_DISCOVERABLE;
-
- err = set_mode(adapter, mode);
- if (err < 0 && msg)
- return failed_strerror(msg, -err);
-
done:
return msg ? dbus_message_new_method_return(msg) : NULL;
}
@@ -623,6 +653,13 @@
{
struct btd_adapter *adapter = req->adapter;
+ /* Ignore set_mode session */
+ if (req->owner == NULL)
+ return;
+
+ DBG("%s session %p with %s deactivated",
+ req->mode ? "Mode" : "Discovery", req, req->owner);
+
if (req->mode) {
uint8_t mode;
@@ -634,9 +671,9 @@
if (mode == adapter->mode)
return;
- debug("Switching to '%s' mode", mode2str(mode));
+ DBG("Switching to '%s' mode", mode2str(mode));
- set_mode(adapter, mode);
+ set_mode(adapter, mode, NULL);
} else {
adapter->disc_sessions = g_slist_remove(adapter->disc_sessions,
req);
@@ -644,7 +681,7 @@
if (adapter->disc_sessions)
return;
- debug("Stopping discovery");
+ DBG("Stopping discovery");
pending_remote_name_cancel(adapter);
@@ -653,8 +690,10 @@
g_slist_free(adapter->oor_devices);
adapter->oor_devices = NULL;
- if (adapter->scheduler_id)
+ if (adapter->scheduler_id) {
g_source_remove(adapter->scheduler_id);
+ adapter->scheduler_id = 0;
+ }
adapter_ops->stop_discovery(adapter->dev_id);
}
@@ -662,9 +701,6 @@
static void session_free(struct session_req *req)
{
- debug("%s session %p with %s deactivated",
- req->mode ? "Mode" : "Discovery", req, req->owner);
-
if (req->id)
g_dbus_remove_watch(req->conn, req->id);
@@ -687,20 +723,11 @@
session_free(req);
}
-static struct session_req *session_ref(struct session_req *req)
-{
- req->refcount++;
-
- debug("session_ref(%p): ref=%d", req, req->refcount);
-
- return req;
-}
-
static void session_unref(struct session_req *req)
{
req->refcount--;
- debug("session_unref(%p): ref=%d", req, req->refcount);
+ DBG("%p: ref=%d", req, req->refcount);
if (req->refcount)
return;
@@ -708,30 +735,6 @@
session_free(req);
}
-static struct session_req *create_session(struct btd_adapter *adapter,
- DBusConnection *conn, DBusMessage *msg,
- uint8_t mode, GDBusWatchFunction cb)
-{
- struct session_req *req;
- const char *sender = dbus_message_get_sender(msg);
-
- req = g_new0(struct session_req, 1);
- req->adapter = adapter;
- req->conn = dbus_connection_ref(conn);
- req->msg = dbus_message_ref(msg);
- req->owner = g_strdup(dbus_message_get_sender(msg));
- req->mode = mode;
-
- if (cb)
- req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req,
- NULL);
-
- info("%s session %p with %s activated",
- req->mode ? "Mode" : "Discovery", req, sender);
-
- return session_ref(req);
-}
-
static void confirm_mode_cb(struct agent *agent, DBusError *derr, void *data)
{
struct session_req *req = data;
@@ -746,7 +749,7 @@
return;
}
- err = set_mode(req->adapter, req->mode);
+ err = set_mode(req->adapter, req->mode, NULL);
if (err < 0)
reply = failed_strerror(req->msg, -err);
else
@@ -831,7 +834,9 @@
return;
if (dev->ssp_mode > 0)
- create_ext_inquiry_response((char *) dev->name, data);
+ create_ext_inquiry_response((char *) dev->name,
+ adapter->tx_power,
+ adapter->services, data);
if (hci_write_ext_inquiry_response(dd, fec, data,
HCI_REQ_TIMEOUT) < 0)
@@ -841,6 +846,78 @@
hci_close_dev(dd);
}
+void adapter_set_class_complete(bdaddr_t *bdaddr, uint8_t status)
+{
+ uint8_t class[3];
+ struct btd_adapter *adapter;
+ int err;
+
+ if (status)
+ return;
+
+ adapter = manager_find_adapter(bdaddr);
+ if (!adapter) {
+ error("Unable to find matching adapter");
+ return;
+ }
+
+ if (adapter->pending_cod == 0)
+ return;
+
+ adapter->current_cod = adapter->pending_cod;
+ adapter->pending_cod = 0;
+
+ class[2] = (adapter->current_cod >> 16) & 0xff;
+ class[1] = (adapter->current_cod >> 8) & 0xff;
+ class[0] = adapter->current_cod & 0xff;
+
+ write_local_class(&adapter->bdaddr, class);
+
+ emit_property_changed(connection, adapter->path,
+ ADAPTER_INTERFACE, "Class",
+ DBUS_TYPE_UINT32, &adapter->current_cod);
+
+ update_ext_inquiry_response(adapter);
+
+ if (adapter->wanted_cod == adapter->current_cod)
+ return;
+
+ if (adapter->wanted_cod & LIMITED_BIT &&
+ !(adapter->current_cod & LIMITED_BIT))
+ err = adapter_ops->set_limited_discoverable(adapter->dev_id,
+ adapter->wanted_cod, TRUE);
+ else if (!(adapter->wanted_cod & LIMITED_BIT) &&
+ adapter->current_cod & LIMITED_BIT)
+ err = adapter_ops->set_limited_discoverable(adapter->dev_id,
+ adapter->wanted_cod, FALSE);
+ else
+ err = adapter_ops->set_class(adapter->dev_id,
+ adapter->wanted_cod);
+
+ if (err == 0)
+ adapter->pending_cod = adapter->wanted_cod;
+}
+
+void adapter_update_tx_power(bdaddr_t *bdaddr, uint8_t status, void *ptr)
+{
+ struct btd_adapter *adapter;
+
+ if (status)
+ return;
+
+ adapter = manager_find_adapter(bdaddr);
+ if (!adapter) {
+ error("Unable to find matching adapter");
+ return;
+ }
+
+ adapter->tx_power = *((int8_t *) ptr);
+
+ DBG("inquiry respone tx power level is %d", adapter->tx_power);
+
+ update_ext_inquiry_response(adapter);
+}
+
void adapter_update_local_name(bdaddr_t *bdaddr, uint8_t status, void *ptr)
{
read_local_name_rp rp;
@@ -872,8 +949,9 @@
name = g_strdup((char *) dev->name);
if (connection)
- emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
- "Name", DBUS_TYPE_STRING, &name);
+ emit_property_changed(connection, adapter->path,
+ ADAPTER_INTERFACE, "Name",
+ DBUS_TYPE_STRING, &name);
g_free(name);
}
@@ -903,7 +981,6 @@
{
struct btd_adapter *adapter = data;
struct hci_dev *dev = &adapter->dev;
- int err;
if (!g_utf8_validate(name, -1, NULL)) {
error("Name change failed: supplied name isn't valid UTF-8");
@@ -913,12 +990,14 @@
if (strncmp(name, (char *) dev->name, MAX_NAME_LENGTH) == 0)
goto done;
- if (!adapter->up)
- return failed_strerror(msg, -EHOSTDOWN);
-
- err = adapter_ops->set_name(adapter->dev_id, name);
- if (err < 0)
- return failed_strerror(msg, err);
+ if (!adapter->up) {
+ strncpy((char *) adapter->dev.name, name, MAX_NAME_LENGTH);
+ write_local_name(&adapter->bdaddr, name);
+ } else {
+ int err = adapter_ops->set_name(adapter->dev_id, name);
+ if (err < 0)
+ return failed_strerror(msg, err);
+ }
done:
return dbus_message_new_method_return(msg);
@@ -977,6 +1056,79 @@
g_free(devices);
}
+static void adapter_emit_uuids_updated(struct btd_adapter *adapter)
+{
+ char **uuids;
+ int i;
+ sdp_list_t *list;
+
+ uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+
+ for (i = 0, list = adapter->services; list; list = list->next, i++) {
+ sdp_record_t *rec = list->data;
+ uuids[i] = bt_uuid2string(&rec->svclass);
+ }
+
+ emit_array_property_changed(connection, adapter->path,
+ ADAPTER_INTERFACE, "UUIDs", DBUS_TYPE_STRING, &uuids);
+
+ g_strfreev(uuids);
+}
+
+/*
+ * adapter_services_inc_rem - Insert or remove UUID from adapter
+ */
+static void adapter_service_ins_rem(const bdaddr_t *bdaddr, void *rec,
+ gboolean insert)
+{
+ struct btd_adapter *adapter;
+ GSList *adapters;
+
+ adapters = NULL;
+
+ if (bacmp(bdaddr, BDADDR_ANY) != 0) {
+ /* Only one adapter */
+ adapter = manager_find_adapter(bdaddr);
+ if (!adapter)
+ return;
+
+ adapters = g_slist_append(adapters, adapter);
+ } else
+ /* Emit D-Bus msg to all adapters */
+ adapters = manager_get_adapters();
+
+ for (; adapters; adapters = adapters->next) {
+ adapter = adapters->data;
+
+ if (insert == TRUE)
+ adapter->services = sdp_list_insert_sorted(
+ adapter->services, rec,
+ record_sort);
+ else
+ adapter->services = sdp_list_remove(adapter->services,
+ rec);
+
+ adapter_emit_uuids_updated(adapter);
+ }
+}
+
+void adapter_service_insert(const bdaddr_t *bdaddr, void *rec)
+{
+ /* TRUE to include service*/
+ adapter_service_ins_rem(bdaddr, rec, TRUE);
+}
+
+void adapter_service_remove(const bdaddr_t *bdaddr, void *rec)
+{
+ /* FALSE to remove service*/
+ adapter_service_ins_rem(bdaddr, rec, FALSE);
+}
+
+sdp_list_t *adapter_get_services(struct btd_adapter *adapter)
+{
+ return adapter->services;
+}
+
struct btd_device *adapter_create_device(DBusConnection *conn,
struct btd_adapter *adapter,
const char *address)
@@ -984,7 +1136,7 @@
struct btd_device *device;
const char *path;
- debug("adapter_create_device(%s)", address);
+ DBG("%s", address);
device = device_create(conn, adapter, address);
if (!device)
@@ -1006,7 +1158,8 @@
}
void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
- struct btd_device *device)
+ struct btd_device *device,
+ gboolean remove_storage)
{
const gchar *dev_path = device_get_path(device);
struct agent *agent;
@@ -1022,20 +1175,11 @@
DBUS_TYPE_INVALID);
agent = device_get_agent(device);
- if (!agent)
- agent = adapter->agent;
if (agent && device_is_authorizing(device))
agent_cancel(agent);
- agent = device_get_agent(device);
-
- if (agent) {
- agent_destroy(agent, FALSE);
- device_set_agent(device, NULL);
- }
-
- device_remove(device, conn, TRUE);
+ device_remove(device, remove_storage);
}
struct btd_device *adapter_get_device(DBusConnection *conn,
@@ -1044,7 +1188,7 @@
{
struct btd_device *device;
- debug("adapter_get_device(%s)", address);
+ DBG("%s", address);
if (!adapter)
return NULL;
@@ -1138,11 +1282,11 @@
DBusMessageIter iter;
DBusMessageIter dict;
char str[MAX_NAME_LENGTH + 1], srcaddr[18];
- uint32_t class;
gboolean value;
- char **devices;
+ char **devices, **uuids;
int i;
GSList *l;
+ sdp_list_t *list;
ba2str(&adapter->bdaddr, srcaddr);
@@ -1172,10 +1316,8 @@
dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &property);
/* Class */
- class = adapter->dev.class[0] |
- adapter->dev.class[1] << 8 |
- adapter->dev.class[2] << 16;
- dict_append_entry(&dict, "Class", DBUS_TYPE_UINT32, &class);
+ dict_append_entry(&dict, "Class",
+ DBUS_TYPE_UINT32, &adapter->current_cod);
/* Powered */
value = (adapter->up && !adapter->off_requested) ? TRUE : FALSE;
@@ -1216,6 +1358,18 @@
&devices, i);
g_free(devices);
+ /* UUIDs */
+ uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+
+ for (i = 0, list = adapter->services; list; list = list->next, i++) {
+ sdp_record_t *rec = list->data;
+ uuids[i] = bt_uuid2string(&rec->svclass);
+ }
+
+ dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &uuids, i);
+
+ g_strfreev(uuids);
+
dbus_message_iter_close_container(&iter, &dict);
return reply;
@@ -1310,7 +1464,7 @@
struct session_req *req;
const char *sender = dbus_message_get_sender(msg);
uint8_t new_mode;
- int ret;
+ int err;
if (!adapter->agent)
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
@@ -1336,11 +1490,11 @@
if (adapter->mode >= new_mode)
return dbus_message_new_method_return(msg);
- ret = agent_confirm_mode_change(adapter->agent, mode2str(new_mode),
+ err = agent_confirm_mode_change(adapter->agent, mode2str(new_mode),
confirm_mode_cb, req, NULL);
- if (ret < 0) {
+ if (err < 0) {
session_unref(req);
- return failed_strerror(msg, -ret);
+ return failed_strerror(msg, -err);
}
return NULL;
@@ -1414,9 +1568,7 @@
device = adapter_find_device(adapter, address);
if (!device || !device_is_creating(device, NULL))
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".NotInProgress",
- "Device creation not in progress");
+ return not_in_progress(msg, "Device creation not in progress");
if (!device_is_creating(device, sender))
return not_authorized(msg);
@@ -1428,7 +1580,7 @@
return NULL;
}
- adapter_remove_device(conn, adapter, device);
+ adapter_remove_device(conn, adapter, device, TRUE);
return dbus_message_new_method_return(msg);
}
@@ -1452,7 +1604,7 @@
ERROR_INTERFACE ".AlreadyExists",
"Device already exists");
- debug("create_device(%s)", address);
+ DBG("%s", address);
device = adapter_create_device(conn, adapter, address);
if (!device)
@@ -1489,7 +1641,7 @@
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)
+ DBUS_TYPE_INVALID) == FALSE)
return invalid_args(msg);
if (check_address(address) < 0)
@@ -1522,8 +1674,8 @@
return strcasecmp(dev_path, path);
}
-static DBusMessage *remove_device(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
+ void *data)
{
struct btd_adapter *adapter = data;
struct btd_device *device;
@@ -1550,7 +1702,7 @@
device_set_temporary(device, TRUE);
if (!device_is_connected(device)) {
- adapter_remove_device(conn, adapter, device);
+ adapter_remove_device(conn, adapter, device, TRUE);
return dbus_message_new_method_return(msg);
}
@@ -1558,8 +1710,8 @@
return NULL;
}
-static DBusMessage *find_device(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
+ void *data)
{
struct btd_adapter *adapter = data;
struct btd_device *device;
@@ -1599,8 +1751,8 @@
adapter->agent = NULL;
}
-static DBusMessage *register_agent(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
+ void *data)
{
const char *path, *name, *capability;
struct agent *agent;
@@ -1631,14 +1783,14 @@
adapter->agent = agent;
- debug("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
+ DBG("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
path);
return dbus_message_new_method_return(msg);
}
-static DBusMessage *unregister_agent(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
+ void *data)
{
const char *path, *name;
struct btd_adapter *adapter = data;
@@ -1651,10 +1803,10 @@
if (!adapter->agent || !agent_matches(adapter->agent, name, path))
return g_dbus_create_error(msg,
- ERROR_INTERFACE ".DoesNotExist",
- "No such agent");
+ ERROR_INTERFACE ".DoesNotExist",
+ "No such agent");
- agent_destroy(adapter->agent, FALSE);
+ agent_free(adapter->agent);
adapter->agent = NULL;
return dbus_message_new_method_return(msg);
@@ -1896,13 +2048,14 @@
return 0;
}
-static int adapter_setup(struct btd_adapter *adapter)
+static int adapter_setup(struct btd_adapter *adapter, const char *mode)
{
struct hci_dev *dev = &adapter->dev;
uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00 };
uint8_t inqmode;
int err , dd;
char name[MAX_NAME_LENGTH + 1];
+ uint8_t cls[3];
dd = hci_open_dev(adapter->dev_id);
if (dd < 0) {
@@ -1945,9 +2098,6 @@
sizeof(events), events);
}
- if (read_local_name(&adapter->bdaddr, name) == 0)
- adapter_ops->set_name(adapter->dev_id, name);
-
inqmode = get_inquiry_mode(dev);
if (inqmode < 1)
goto done;
@@ -1960,6 +2110,31 @@
return err;
}
+ if (dev->features[7] & LMP_INQ_TX_PWR)
+ hci_send_cmd(dd, OGF_HOST_CTL,
+ OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
+
+ if (read_local_name(&adapter->bdaddr, name) < 0)
+ expand_name(name, MAX_NAME_LENGTH, main_opts.name,
+ adapter->dev_id);
+
+ adapter_ops->set_name(adapter->dev_id, name);
+ if (g_str_equal(mode, "off"))
+ strncpy((char *) adapter->dev.name, name, MAX_NAME_LENGTH);
+
+ /* Set device class */
+ if (adapter->initialized && adapter->wanted_cod) {
+ cls[1] = (adapter->wanted_cod >> 8) & 0xff;
+ cls[0] = adapter->wanted_cod & 0xff;
+ } else if (read_local_class(&adapter->bdaddr, cls) < 0) {
+ uint32_t class = htobl(main_opts.class);
+ if (class)
+ memcpy(cls, &class, 3);
+ else
+ goto done;
+ }
+
+ btd_adapter_set_class(adapter, cls[1], cls[0]);
done:
hci_close_dev(dd);
return 0;
@@ -1971,10 +2146,6 @@
struct btd_adapter *adapter = user_data;
GSList *uuids = bt_string2list(value);
struct btd_device *device;
- bdaddr_t dst;
- char srcaddr[18], dstaddr[18];
-
- ba2str(&adapter->bdaddr, srcaddr);
if (g_slist_find_custom(adapter->devices,
key, (GCompareFunc) device_address_cmp))
@@ -1987,9 +2158,6 @@
device_set_temporary(device, FALSE);
adapter->devices = g_slist_append(adapter->devices, device);
- device_get_address(device, &dst);
- ba2str(&dst, dstaddr);
-
device_probe_drivers(device, uuids);
g_slist_foreach(uuids, (GFunc) g_free, NULL);
@@ -1997,7 +2165,24 @@
}
static void create_stored_device_from_linkkeys(char *key, char *value,
- void *user_data)
+ 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);
+ if (device) {
+ device_set_temporary(device, FALSE);
+ adapter->devices = g_slist_append(adapter->devices, device);
+ }
+}
+
+static void create_stored_device_from_blocked(char *key, char *value,
+ void *user_data)
{
struct btd_adapter *adapter = user_data;
struct btd_device *device;
@@ -2027,6 +2212,26 @@
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
textfile_foreach(filename, create_stored_device_from_linkkeys,
adapter);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
+ textfile_foreach(filename, create_stored_device_from_blocked, adapter);
+}
+
+static void clear_blocked(struct btd_adapter *adapter)
+{
+ int dd;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("hci_open_dev(hci%d): %s (%d)", adapter->dev_id,
+ strerror(errno), errno);
+ return;
+ }
+
+ if (ioctl(dd, HCIUNBLOCKADDR, BDADDR_ANY) < 0)
+ error("ioctl(HCIUNBLOCKADDR): %s (%d)", strerror(errno), errno);
+
+ hci_close_dev(dd);
}
static void probe_driver(gpointer data, gpointer user_data)
@@ -2113,9 +2318,34 @@
return main_opts.pairto;
}
-static int adapter_up(struct btd_adapter *adapter)
+static void adapter_disable_cod_cache(struct btd_adapter *adapter)
{
- char mode[14], srcaddr[18];
+ int err;
+
+ if (!adapter)
+ return;
+
+ if (!adapter->cache_enable)
+ return;
+
+ /* Disable and flush svc cache. All successive service class updates
+ will be written to the device */
+ adapter->cache_enable = FALSE;
+
+ if (adapter->current_cod == adapter->wanted_cod)
+ return;
+
+ err = adapter_ops->set_class(adapter->dev_id, adapter->wanted_cod);
+ if (err < 0)
+ error("Adapter class update failed: %s(%d)",
+ strerror(err), err);
+ else
+ adapter->pending_cod = adapter->wanted_cod;
+}
+
+static int adapter_up(struct btd_adapter *adapter, const char *mode)
+{
+ char srcaddr[18];
uint8_t scan_mode;
gboolean powered, dev_down = FALSE;
int err;
@@ -2136,19 +2366,9 @@
if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
adapter->pairable = TRUE;
- if (!adapter->initialized && !main_opts.remember_powered) {
- if (main_opts.mode == MODE_OFF)
- strcpy(mode, "off");
- else
- strcpy(mode, "connectable");
- } else if (read_device_mode(srcaddr, mode, sizeof(mode)) < 0) {
- if (!adapter->initialized && main_opts.mode == MODE_OFF)
- strcpy(mode, "off");
- else
- goto proceed;
- }
-
if (g_str_equal(mode, "off")) {
+ char onmode[14];
+
powered = FALSE;
if (!adapter->initialized) {
@@ -2156,13 +2376,13 @@
goto proceed;
}
- if (read_on_mode(srcaddr, mode, sizeof(mode)) < 0 ||
- g_str_equal(mode, "off"))
- write_device_mode(&adapter->bdaddr, "connectable");
- else
- write_device_mode(&adapter->bdaddr, mode);
+ if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0 ||
+ g_str_equal(onmode, "off"))
+ strcpy(onmode, "connectable");
- return adapter_up(adapter);
+ write_device_mode(&adapter->bdaddr, onmode);
+
+ return adapter_up(adapter, onmode);
} else if (!g_str_equal(mode, "connectable") &&
adapter->discov_timeout == 0) {
/* Set discoverable only if timeout is 0 */
@@ -2181,6 +2401,7 @@
if (adapter->initialized == FALSE) {
load_drivers(adapter);
+ clear_blocked(adapter);
load_devices(adapter);
/* retrieve the active connections: address the scenario where
@@ -2202,7 +2423,8 @@
ADAPTER_INTERFACE, "Powered",
DBUS_TYPE_BOOLEAN, &powered);
- adapter_disable_svc_cache(adapter);
+ adapter_disable_cod_cache(adapter);
+
return 0;
}
@@ -2213,6 +2435,7 @@
struct hci_version ver;
uint8_t features[8];
int dd, err;
+ char mode[14], address[18];
if (hci_devinfo(adapter->dev_id, &di) < 0)
return -errno;
@@ -2225,7 +2448,7 @@
if (!bacmp(&di.bdaddr, BDADDR_ANY)) {
int err;
- debug("Adapter %s without an address", adapter->path);
+ DBG("Adapter %s without an address", adapter->path);
err = adapter_read_bdaddr(adapter->dev_id, &di.bdaddr);
if (err < 0)
@@ -2234,6 +2457,16 @@
bacpy(&adapter->bdaddr, &di.bdaddr);
memcpy(dev->features, di.features, 8);
+ ba2str(&adapter->bdaddr, address);
+
+ err = read_device_mode(address, mode, sizeof(mode));
+
+ if ((!adapter->initialized && !main_opts.remember_powered) || err < 0) {
+ if (!adapter->initialized && main_opts.mode == MODE_OFF)
+ strcpy(mode, "off");
+ else
+ strcpy(mode, "connectable");
+ }
dd = hci_open_dev(adapter->dev_id);
if (dd < 0) {
@@ -2266,14 +2499,6 @@
memcpy(dev->features, features, 8);
- if (hci_read_class_of_dev(dd, dev->class, HCI_REQ_TIMEOUT) < 0) {
- err = -errno;
- error("Can't read class of adapter on %s: %s (%d)",
- adapter->path, strerror(errno), errno);
- hci_close_dev(dd);
- return err;
- }
-
adapter_ops->read_name(adapter->dev_id);
if (!(features[6] & LMP_SIMPLE_PAIR))
@@ -2296,14 +2521,16 @@
0, NULL);
hci_close_dev(dd);
- adapter_setup(adapter);
+ adapter->current_cod = 0;
+
+ adapter_setup(adapter, mode);
if (!adapter->initialized && adapter->already_up) {
- debug("Stopping Inquiry at adapter startup");
+ DBG("Stopping Inquiry at adapter startup");
adapter_ops->stop_discovery(adapter->dev_id);
}
- err = adapter_up(adapter);
+ err = adapter_up(adapter, mode);
info("Adapter %s has been enabled", adapter->path);
@@ -2400,6 +2627,7 @@
adapter->mode = MODE_OFF;
adapter->state = DISCOVER_TYPE_NONE;
adapter->cache_enable = TRUE;
+ adapter->pending_cod = 0;
info("Adapter %s has been disabled", adapter->path);
@@ -2413,60 +2641,7 @@
if (dev->ignore)
return 0;
- if (adapter->cache_enable) {
- adapter->svc_cache = new_svc;
- return 0;
- }
-
- set_service_classes(adapter, new_svc);
-
- update_ext_inquiry_response(adapter);
-
- return 0;
-}
-
-void adapter_disable_svc_cache(struct btd_adapter *adapter)
-{
- if (!adapter)
- return;
-
- if (!adapter->cache_enable)
- return;
-
- /* Disable and flush svc cache. All successive service class updates
- will be written to the device */
- adapter->cache_enable = FALSE;
-
- set_service_classes(adapter, adapter->svc_cache);
-
- update_ext_inquiry_response(adapter);
-}
-
-int adapter_get_class(struct btd_adapter *adapter, uint8_t *cls)
-{
- struct hci_dev *dev = &adapter->dev;
-
- memcpy(cls, dev->class, 3);
-
- return 0;
-}
-
-int adapter_set_class(struct btd_adapter *adapter, uint8_t *cls)
-{
- struct hci_dev *dev = &adapter->dev;
- uint32_t class;
-
- if (memcmp(dev->class, cls, 3) == 0)
- return 0;
-
- memcpy(dev->class, cls, 3);
-
- write_local_class(&adapter->bdaddr, cls);
-
- class = cls[0] | (cls[1] << 8) | (cls[2] << 16);
-
- emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
- "Class", DBUS_TYPE_UINT32, &class);
+ adapter_set_service_classes(adapter, new_svc);
return 0;
}
@@ -2486,10 +2661,13 @@
{
struct btd_adapter *adapter = user_data;
- agent_destroy(adapter->agent, FALSE);
+ agent_free(adapter->agent);
adapter->agent = NULL;
- debug("adapter_free(%p)", adapter);
+ DBG("%p", adapter);
+
+ if (adapter->auth_idle_id)
+ g_source_remove(adapter->auth_idle_id);
g_free(adapter->path);
g_free(adapter);
@@ -2499,7 +2677,7 @@
{
adapter->ref++;
- debug("btd_adapter_ref(%p): ref=%d", adapter, adapter->ref);
+ DBG("%p: ref=%d", adapter, adapter->ref);
return adapter;
}
@@ -2510,7 +2688,7 @@
adapter->ref--;
- debug("btd_adapter_unref(%p): ref=%d", adapter, adapter->ref);
+ DBG("%p: ref=%d", adapter, adapter->ref);
if (adapter->ref > 0)
return;
@@ -2546,6 +2724,8 @@
adapter->path = g_strdup(path);
adapter->already_up = devup;
+ adapter->tx_power = 0;
+
if (!g_dbus_register_interface(conn, path, ADAPTER_INTERFACE,
adapter_methods, adapter_signals, NULL,
adapter, adapter_free)) {
@@ -2561,13 +2741,14 @@
{
GSList *l;
- debug("Removing adapter %s", adapter->path);
+ DBG("Removing adapter %s", adapter->path);
for (l = adapter->devices; l; l = l->next)
- device_remove(l->data, connection, FALSE);
+ device_remove(l->data, FALSE);
g_slist_free(adapter->devices);
- unload_drivers(adapter);
+ if (adapter->initialized)
+ unload_drivers(adapter);
/* Return adapter to down state if it was not up on init */
if (adapter->up && !adapter->already_up)
@@ -2758,13 +2939,13 @@
dev = adapter_search_found_devices(adapter, &match);
if (dev) {
- if (rssi == dev->rssi)
- return;
-
/* Out of range list update */
adapter->oor_devices = g_slist_remove(adapter->oor_devices,
dev);
+ if (rssi == dev->rssi)
+ return;
+
goto done;
}
@@ -2822,7 +3003,8 @@
DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_INVALID);
- adapter->found_devices = g_slist_remove(adapter->found_devices, dev);
+ adapter->found_devices = g_slist_remove(adapter->found_devices,
+ dev);
dev_info_free(dev);
}
@@ -2832,11 +3014,49 @@
adapter->oor_devices = g_slist_copy(adapter->found_devices);
}
+static void set_mode_complete(struct btd_adapter *adapter)
+{
+ struct session_req *pending;
+ const char *modestr;
+ int err;
+
+ if (adapter->pending_mode == NULL)
+ return;
+
+ pending = adapter->pending_mode;
+ adapter->pending_mode = NULL;
+
+ err = (pending->mode != adapter->mode) ? -EINVAL : 0;
+
+ if (pending->msg != NULL) {
+ DBusMessage *msg = pending->msg;
+ DBusMessage *reply;
+
+ if (err < 0)
+ reply = failed_strerror(msg, -err);
+ else
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+ g_dbus_send_message(connection, reply);
+ }
+
+ modestr = mode2str(adapter->mode);
+
+ DBG("%s", modestr);
+
+ /* Only store if the mode matches the pending */
+ if (err == 0)
+ write_device_mode(&adapter->bdaddr, modestr);
+ else
+ error("unable to set mode: %s", mode2str(pending->mode));
+
+ session_unref(pending);
+}
+
void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
{
const gchar *path = adapter_get_path(adapter);
gboolean discoverable, pairable;
- uint8_t real_class[3];
if (adapter->scan_mode == scan_mode)
return;
@@ -2881,23 +3101,19 @@
ADAPTER_INTERFACE, "Pairable",
DBUS_TYPE_BOOLEAN, &pairable);
- memcpy(real_class, adapter->dev.class, 3);
- if (adapter->svc_cache)
- real_class[2] = adapter->svc_cache;
-
if (discoverable && adapter->pairable && adapter->discov_timeout > 0 &&
adapter->discov_timeout <= 60)
- adapter_ops->set_limited_discoverable(adapter->dev_id,
- real_class, TRUE);
+ adapter_set_limited_discoverable(adapter, TRUE);
else if (!discoverable)
- adapter_ops->set_limited_discoverable(adapter->dev_id,
- real_class, FALSE);
+ adapter_set_limited_discoverable(adapter, FALSE);
emit_property_changed(connection, path,
ADAPTER_INTERFACE, "Discoverable",
DBUS_TYPE_BOOLEAN, &discoverable);
adapter->scan_mode = scan_mode;
+
+ set_mode_complete(adapter);
}
struct agent *adapter_get_agent(struct btd_adapter *adapter)
@@ -2945,8 +3161,8 @@
if (device_is_temporary(device)) {
const char *path = device_get_path(device);
- debug("Removing temporary device %s", path);
- adapter_remove_device(connection, adapter, device);
+ DBG("Removing temporary device %s", path);
+ adapter_remove_device(connection, adapter, device, TRUE);
}
}
@@ -2988,6 +3204,18 @@
auth->cb(derr, auth->user_data);
}
+static gboolean auth_idle_cb(gpointer user_data)
+{
+ struct service_auth *auth = user_data;
+ struct btd_adapter *adapter = auth->adapter;
+
+ adapter->auth_idle_id = 0;
+
+ auth->cb(NULL, auth->user_data);
+
+ return FALSE;
+}
+
static int btd_adapter_authorize(struct btd_adapter *adapter,
const bdaddr_t *dst,
const char *uuid,
@@ -2997,7 +3225,6 @@
struct btd_device *device;
struct agent *agent;
char address[18];
- gboolean trusted;
const gchar *dev_path;
int err;
@@ -3010,24 +3237,8 @@
if (!g_slist_find(adapter->connections, device))
return -ENOTCONN;
- trusted = read_trust(&adapter->bdaddr, address, GLOBAL_TRUST);
-
- if (trusted) {
- cb(NULL, user_data);
- return 0;
- }
-
- device = adapter_find_device(adapter, address);
- if (!device)
- return -EPERM;
-
- agent = device_get_agent(device);
-
- if (!agent)
- agent = adapter->agent;
-
- if (!agent)
- return -EPERM;
+ if (adapter->auth_idle_id)
+ return -EBUSY;
auth = g_try_new0(struct service_auth, 1);
if (!auth)
@@ -3036,12 +3247,27 @@
auth->cb = cb;
auth->user_data = user_data;
auth->device = device;
+ auth->adapter = adapter;
+
+ 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;
+ }
+
+ agent = device_get_agent(device);
+ if (!agent) {
+ g_free(auth);
+ return -EPERM;
+ }
dev_path = device_get_path(device);
err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, auth, g_free);
-
- if (err == 0)
+ if (err < 0)
+ g_free(auth);
+ else
device_set_authorizing(device, TRUE);
return err;
@@ -3097,16 +3323,18 @@
if (!device)
return -EPERM;
+ if (adapter->auth_idle_id) {
+ g_source_remove(adapter->auth_idle_id);
+ adapter->auth_idle_id = 0;
+ return 0;
+ }
+
/*
* FIXME: Cancel fails if authorization is requested to adapter's
* agent and in the meanwhile CreatePairedDevice is called.
*/
agent = device_get_agent(device);
-
- if (!agent)
- agent = adapter->agent;
-
if (!agent)
return -EPERM;
@@ -3179,6 +3407,17 @@
return adapter_ops->set_powered(adapter->dev_id, TRUE);
}
+int btd_adapter_switch_online(struct btd_adapter *adapter)
+{
+ if (!adapter_ops)
+ return -EINVAL;
+
+ if (adapter->up)
+ return 0;
+
+ return adapter_ops->set_powered(adapter->dev_id, TRUE);
+}
+
int btd_adapter_switch_offline(struct btd_adapter *adapter)
{
if (!adapter_ops)
diff --git a/src/adapter.h b/src/adapter.h
index 83f987e..8226514 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -23,6 +23,7 @@
*/
#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
#include <dbus/dbus.h>
#include <glib.h>
@@ -69,7 +70,6 @@
uint8_t ssp_mode;
uint8_t name[MAX_NAME_LENGTH];
- uint8_t class[3];
};
int adapter_start(struct btd_adapter *adapter);
@@ -78,10 +78,6 @@
int adapter_update(struct btd_adapter *adapter, uint8_t cls);
-int adapter_get_class(struct btd_adapter *adapter, uint8_t *cls);
-
-int adapter_set_class(struct btd_adapter *adapter, uint8_t *cls);
-
int adapter_update_ssp_mode(struct btd_adapter *adapter, uint8_t mode);
struct btd_device *adapter_get_device(DBusConnection *conn,
@@ -91,10 +87,9 @@
struct btd_device *adapter_find_connection(struct btd_adapter *adapter, uint16_t handle);
-void adapter_disable_svc_cache(struct btd_adapter *adapter);
-
void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
- struct btd_device *device);
+ struct btd_device *device,
+ gboolean remove_storage);
struct btd_device *adapter_create_device(DBusConnection *conn,
struct btd_adapter *adapter, const char *address);
@@ -125,7 +120,12 @@
void adapter_update_oor_devices(struct btd_adapter *adapter);
void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode);
void adapter_setname_complete(bdaddr_t *local, uint8_t status);
+void adapter_update_tx_power(bdaddr_t *bdaddr, uint8_t status, void *ptr);
void adapter_update_local_name(bdaddr_t *bdaddr, uint8_t status, void *ptr);
+void adapter_service_insert(const bdaddr_t *bdaddr, void *rec);
+void adapter_service_remove(const bdaddr_t *bdaddr, void *rec);
+sdp_list_t *adapter_get_services(struct btd_adapter *adapter);
+void adapter_set_class_complete(bdaddr_t *bdaddr, uint8_t status);
struct agent *adapter_get_agent(struct btd_adapter *adapter);
void adapter_add_connection(struct btd_adapter *adapter,
@@ -136,8 +136,9 @@
struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter);
void btd_adapter_unref(struct btd_adapter *adapter);
-int set_major_and_minor_class(struct btd_adapter *adapter, uint8_t major,
- uint8_t minor);
+
+int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
+ uint8_t minor);
struct btd_adapter_driver {
@@ -162,6 +163,7 @@
gboolean adapter_powering_down(struct btd_adapter *adapter);
int btd_adapter_restore_powered(struct btd_adapter *adapter);
+int btd_adapter_switch_online(struct btd_adapter *adapter);
int btd_adapter_switch_offline(struct btd_adapter *adapter);
struct btd_adapter_ops {
@@ -172,7 +174,7 @@
int (*set_powered) (int index, gboolean powered);
int (*set_connectable) (int index);
int (*set_discoverable) (int index);
- int (*set_limited_discoverable) (int index, const uint8_t *cls,
+ int (*set_limited_discoverable) (int index, uint32_t class,
gboolean limited);
int (*start_discovery) (int index, gboolean periodic);
int (*stop_discovery) (int index);
@@ -180,6 +182,7 @@
int (*cancel_resolve_name) (int index, bdaddr_t *bdaddr);
int (*set_name) (int index, const char *name);
int (*read_name) (int index);
+ int (*set_class) (int index, uint32_t class);
};
int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops);
diff --git a/src/agent.c b/src/agent.c
index 4f9ba82..efa0320 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2008 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -41,7 +41,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "hcid.h"
#include "adapter.h"
@@ -90,7 +90,7 @@
{
DBusMessage *message;
- debug("Releasing agent %s, %s", agent->name, agent->path);
+ DBG("Releasing agent %s, %s", agent->name, agent->path);
if (agent->request)
agent_cancel(agent);
@@ -138,12 +138,14 @@
{
struct agent *agent = user_data;
- debug("Agent exited without calling Unregister");
+ DBG("Agent exited without calling Unregister");
- agent_destroy(agent, TRUE);
+ agent->exited = TRUE;
+
+ agent_free(agent);
}
-static void agent_free(struct agent *agent)
+void agent_free(struct agent *agent)
{
if (!agent)
return;
@@ -207,16 +209,6 @@
return agent;
}
-int agent_destroy(struct agent *agent, gboolean exited)
-{
- if (!agent)
- return 0;
-
- agent->exited = exited;
- agent_free(agent);
- return 0;
-}
-
static struct agent_request *agent_request_new(struct agent *agent,
agent_request_type_t type,
void *cb,
@@ -358,7 +350,7 @@
agent->request = req;
- debug("authorize request was sent for %s", path);
+ DBG("authorize request was sent for %s", path);
return 0;
}
@@ -521,7 +513,7 @@
if (agent->request)
return -EBUSY;
- debug("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s",
+ 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,
@@ -626,7 +618,7 @@
if (agent->request)
return -EBUSY;
- debug("Calling Agent.RequestPasskey: name=%s, path=%s",
+ DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
agent->name, agent->path);
req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
@@ -685,7 +677,7 @@
if (agent->request)
return -EBUSY;
- debug("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
+ DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
agent->name, agent->path, passkey);
req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
@@ -742,7 +734,7 @@
if (agent->request)
return -EBUSY;
- debug("Calling Agent.RequestPairingConsent: name=%s, path=%s",
+ DBG("Calling Agent.RequestPairingConsent: name=%s, path=%s",
agent->name, agent->path);
req = agent_request_new(agent, AGENT_REQUEST_PAIRING_CONSENT, cb,
diff --git a/src/agent.h b/src/agent.h
index 314baf9..e184250 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2008 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -39,7 +39,7 @@
const char *path, uint8_t capability,
agent_remove_cb cb, void *remove_cb_data);
-int agent_destroy(struct agent *agent, gboolean exited);
+void agent_free(struct agent *agent);
int agent_authorize(struct agent *agent, const char *path,
const char *uuid, agent_cb cb, void *user_data,
diff --git a/common/android_bluez.c b/src/android_bluez.c
similarity index 100%
rename from common/android_bluez.c
rename to src/android_bluez.c
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index c047623..56e7a83 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -11,12 +11,19 @@
<allow own="org.bluez"/>
<allow send_destination="org.bluez"/>
<allow send_interface="org.bluez.Agent"/>
+ <allow send_interface="org.bluez.HandsfreeAgent"/>
</policy>
<policy at_console="true">
<allow send_destination="org.bluez"/>
</policy>
+ <!-- allow users of lp group (printing subsystem) to
+ communicate with bluetoothd -->
+ <policy group="lp">
+ <allow send_destination="org.bluez"/>
+ </policy>
+
<policy context="default">
<deny send_destination="org.bluez"/>
</policy>
diff --git a/common/btio.c b/src/btio.c
similarity index 93%
rename from common/btio.c
rename to src/btio.c
index d7e575d..93079ae 100644
--- a/common/btio.c
+++ b/src/btio.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2009 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
*
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,6 @@
#include <glib.h>
-#include "logging.h"
#include "btio.h"
#define ERROR_FAILED(gerr, str, err) \
@@ -58,6 +57,7 @@
uint16_t imtu;
uint16_t omtu;
int master;
+ uint8_t mode;
};
struct connect {
@@ -182,10 +182,8 @@
srv_sock = g_io_channel_unix_get_fd(io);
cli_sock = accept(srv_sock, NULL, NULL);
- if (cli_sock < 0) {
- error("accept: %s (%d)", strerror(errno), errno);
+ if (cli_sock < 0)
return TRUE;
- }
cli_io = g_io_channel_unix_new(cli_sock);
@@ -252,7 +250,7 @@
(GDestroyNotify) accept_remove);
}
-static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm)
+static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
{
struct sockaddr_l2 addr;
@@ -261,7 +259,12 @@
bacpy(&addr.l2_bdaddr, src);
addr.l2_psm = htobs(psm);
- return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "l2cap_bind", errno);
+ return -1;
+ }
+
+ return 0;
}
static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
@@ -472,10 +475,10 @@
return TRUE;
}
-static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu,
- uint16_t omtu, int master, GError **err)
+static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
+ uint8_t mode, int master, GError **err)
{
- if (imtu || omtu) {
+ if (imtu || omtu || mode) {
struct l2cap_options l2o;
socklen_t len;
@@ -491,6 +494,8 @@
l2o.imtu = imtu;
if (omtu)
l2o.omtu = omtu;
+ if (mode)
+ l2o.mode = mode;
if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
sizeof(l2o)) < 0) {
@@ -510,7 +515,8 @@
return TRUE;
}
-static int rfcomm_bind(int sock, const bdaddr_t *src, uint8_t channel)
+static int rfcomm_bind(int sock,
+ const bdaddr_t *src, uint8_t channel, GError **err)
{
struct sockaddr_rc addr;
@@ -519,7 +525,12 @@
bacpy(&addr.rc_bdaddr, src);
addr.rc_channel = channel;
- return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "rfcomm_bind", errno);
+ return -1;
+ }
+
+ return 0;
}
static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
@@ -552,7 +563,7 @@
return TRUE;
}
-static int sco_bind(int sock, const bdaddr_t *src)
+static int sco_bind(int sock, const bdaddr_t *src, GError **err)
{
struct sockaddr_sco addr;
@@ -560,7 +571,12 @@
addr.sco_family = AF_BLUETOOTH;
bacpy(&addr.sco_bdaddr, src);
- return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "sco_bind", errno);
+ return -1;
+ }
+
+ return 0;
}
static int sco_connect(int sock, const bdaddr_t *dst)
@@ -615,6 +631,8 @@
/* Set defaults */
opts->defer = DEFAULT_DEFER_TIMEOUT;
opts->master = -1;
+ opts->sec_level = BT_IO_SEC_MEDIUM;
+ opts->mode = L2CAP_MODE_BASIC;
while (opt != BT_IO_OPT_INVALID) {
switch (opt) {
@@ -664,6 +682,9 @@
case BT_IO_OPT_MASTER:
opts->master = va_arg(args, gboolean);
break;
+ case BT_IO_OPT_MODE:
+ opts->mode = va_arg(args, int);
+ break;
default:
g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
"Unknown option %d", opt);
@@ -877,6 +898,12 @@
*(va_arg(args, uint8_t *)) = src.rc_channel ?
src.rc_channel : dst.rc_channel;
break;
+ case BT_IO_OPT_SOURCE_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel;
+ break;
+ case BT_IO_OPT_DEST_CHANNEL:
+ *(va_arg(args, uint8_t *)) = dst.rc_channel;
+ break;
case BT_IO_OPT_MASTER:
len = sizeof(flags);
if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
@@ -1068,7 +1095,7 @@
case BT_IO_L2RAW:
case BT_IO_L2CAP:
return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
- opts.master, err);
+ opts.mode, opts.master, err);
case BT_IO_RFCOMM:
return rfcomm_set(sock, opts.sec_level, opts.master, err);
case BT_IO_SCO:
@@ -1106,12 +1133,11 @@
ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
return NULL;
}
- if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0) < 0) {
- ERROR_FAILED(err, "l2cap_bind", errno);
- return NULL;
- }
- if (!l2cap_set(sock, opts->sec_level, 0, 0, -1, err))
- return NULL;
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
+ if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
+ goto failed;
break;
case BT_IO_L2CAP:
sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
@@ -1119,13 +1145,12 @@
ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
return NULL;
}
- if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0) < 0) {
- ERROR_FAILED(err, "l2cap_bind", errno);
- return NULL;
- }
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
- opts->master, err))
- return NULL;
+ opts->mode, opts->master, err))
+ goto failed;
break;
case BT_IO_RFCOMM:
sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
@@ -1134,12 +1159,10 @@
return NULL;
}
if (rfcomm_bind(sock, &opts->src,
- server ? opts->channel : 0) < 0) {
- ERROR_FAILED(err, "rfcomm_bind", errno);
- return NULL;
- }
+ server ? opts->channel : 0, err) < 0)
+ goto failed;
if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
- return NULL;
+ goto failed;
break;
case BT_IO_SCO:
sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
@@ -1147,12 +1170,10 @@
ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
return NULL;
}
- if (sco_bind(sock, &opts->src) < 0) {
- ERROR_FAILED(err, "sco_bind", errno);
- return NULL;
- }
+ if (sco_bind(sock, &opts->src, err) < 0)
+ goto failed;
if (!sco_set(sock, opts->mtu, err))
- return NULL;
+ goto failed;
break;
default:
g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
@@ -1166,6 +1187,11 @@
g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
return io;
+
+failed:
+ close(sock);
+
+ return NULL;
}
GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
diff --git a/common/btio.h b/src/btio.h
similarity index 92%
rename from common/btio.h
rename to src/btio.h
index 2e50d98..81fda8e 100644
--- a/common/btio.h
+++ b/src/btio.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2009 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
*
*
* This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
-#ifndef BT_IO_H
-#define BT_IO_H
#include <glib.h>
@@ -53,6 +51,8 @@
BT_IO_OPT_DEFER_TIMEOUT,
BT_IO_OPT_SEC_LEVEL,
BT_IO_OPT_CHANNEL,
+ BT_IO_OPT_SOURCE_CHANNEL,
+ BT_IO_OPT_DEST_CHANNEL,
BT_IO_OPT_PSM,
BT_IO_OPT_MTU,
BT_IO_OPT_OMTU,
@@ -60,6 +60,7 @@
BT_IO_OPT_MASTER,
BT_IO_OPT_HANDLE,
BT_IO_OPT_CLASS,
+ BT_IO_OPT_MODE,
} BtIOOption;
typedef enum {
@@ -91,4 +92,3 @@
GDestroyNotify destroy, GError **err,
BtIOOption opt1, ...);
-#endif
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 059c91c..1245b4f 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com>
*
*
@@ -42,7 +42,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "manager.h"
#include "adapter.h"
diff --git a/src/dbus-common.h b/src/dbus-common.h
index 67c7178..c1d9264 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -1,8 +1,8 @@
/* *
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/src/dbus-hci.c b/src/dbus-hci.c
index e9a7f96..79bee44 100644
--- a/src/dbus-hci.c
+++ b/src/dbus-hci.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -45,7 +45,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "hcid.h"
@@ -61,7 +61,7 @@
static DBusConnection *connection = NULL;
-static gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
+gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
struct btd_adapter **adapter,
struct btd_device **device,
gboolean create)
@@ -114,6 +114,10 @@
return "audio-card"; /* Headset */
case 0x06:
return "audio-card"; /* Headphone */
+ case 0x0b: /* VCR */
+ case 0x0c: /* Video Camera */
+ case 0x0d: /* Camcorder */
+ return "camera-video";
default:
return "audio-card"; /* Other audio device */
}
@@ -156,8 +160,8 @@
*
*****************************************************************/
-static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,
- struct btd_device *device)
+static void pincode_cb(struct agent *agent, DBusError *err,
+ const char *pincode, struct btd_device *device)
{
struct btd_adapter *adapter = device_get_adapter(device);
pin_code_reply_cp pr;
@@ -214,31 +218,41 @@
pincode_cb);
}
-static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)
+static int confirm_reply(struct btd_adapter *adapter,
+ struct btd_device *device, gboolean success)
{
- struct btd_device *device = user_data;
- struct btd_adapter *adapter = device_get_adapter(device);
- user_confirm_reply_cp cp;
int dd;
+ user_confirm_reply_cp cp;
uint16_t dev_id = adapter_get_dev_id(adapter);
dd = hci_open_dev(dev_id);
if (dd < 0) {
error("Unable to open hci%d", dev_id);
- return;
+ return dd;
}
memset(&cp, 0, sizeof(cp));
device_get_address(device, &cp.bdaddr);
- if (err)
- hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
+ if (success)
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY,
USER_CONFIRM_REPLY_CP_SIZE, &cp);
else
- hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY,
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
USER_CONFIRM_REPLY_CP_SIZE, &cp);
hci_close_dev(dd);
+
+ return 0;
+}
+
+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,
@@ -323,7 +337,7 @@
err = ioctl(dd, HCIGETAUTHINFO, (unsigned long) &req);
if (err < 0) {
- debug("HCIGETAUTHINFO failed: %s (%d)",
+ DBG("HCIGETAUTHINFO failed: %s (%d)",
strerror(errno), errno);
hci_close_dev(dd);
return err;
@@ -341,80 +355,78 @@
{
struct btd_adapter *adapter;
struct btd_device *device;
- uint8_t remcap, remauth, type;
- uint16_t dev_id;
+ struct agent *agent;
+ uint8_t rem_cap, rem_auth, loc_cap, loc_auth;
+ gboolean bonding_initiator;
if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
return -ENODEV;
- dev_id = adapter_get_dev_id(adapter);
-
- if (get_auth_requirements(sba, dba, &type) < 0) {
- int dd;
-
- dd = hci_open_dev(dev_id);
- if (dd < 0) {
- error("Unable to open hci%d", dev_id);
- return -1;
- }
-
- hci_send_cmd(dd, OGF_LINK_CTL,
- OCF_USER_CONFIRM_NEG_REPLY, 6, dba);
-
- hci_close_dev(dd);
-
- return 0;
+ if (get_auth_requirements(sba, dba, &loc_auth) < 0) {
+ error("Unable to get local authentication requirements");
+ goto fail;
}
- debug("confirm authentication requirement is 0x%02x", type);
+ agent = device_get_agent(device);
+ if (agent == NULL) {
+ error("No agent available for user confirmation");
+ goto fail;
+ }
- remcap = device_get_cap(device);
- remauth = device_get_auth(device);
+ loc_cap = agent_get_io_capability(agent);
- debug("remote IO capabilities are 0x%02x", remcap);
- debug("remote authentication requirement is 0x%02x", remauth);
+ DBG("confirm IO capabilities are 0x%02x", loc_cap);
+ DBG("confirm authentication requirement is 0x%02x", loc_auth);
+
+ rem_cap = device_get_cap(device);
+ rem_auth = device_get_auth(device);
+
+ DBG("remote IO capabilities are 0x%02x", rem_cap);
+ DBG("remote authentication requirement is 0x%02x", rem_auth);
+
+ /* 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. */
+ bonding_initiator = device_is_bonding(device, NULL);
+ if (!bonding_initiator && (loc_auth & 0x01) && rem_cap == 0x03) {
+ error("Rejecting request: remote device can't provide MITM");
+ goto fail;
+ }
/* If local IO capabilities are DisplayYesNo and remote IO
* capabiltiies are DisplayOnly or NoInputNoOutput;
* call PairingConsent callback for incoming requests. */
- struct agent *agent = NULL;
agent = device_get_agent(device);
if (!agent) {
agent = adapter_get_agent(adapter);
if ((agent_get_io_capability(agent) & 0x01) &&
- (remcap == 0x00 || remcap == 0x03))
+ (rem_cap == 0x00 || rem_cap == 0x03))
return device_request_authentication(device,
AUTH_TYPE_PAIRING_CONSENT, 0,
pairing_consent_cb);
}
/* If no side requires MITM protection; auto-accept */
- if (!(remauth & 0x01) &&
- (type == 0xff || !(type & 0x01) || remcap == 0x03)) {
- int dd;
+ if ((loc_auth == 0xff || !(loc_auth & 0x01) || rem_cap == 0x03) &&
+ (!(rem_auth & 0x01) || loc_cap == 0x03)) {
+ DBG("auto accept of confirmation");
/* Wait 5 milliseconds before doing auto-accept */
usleep(5000);
- dd = hci_open_dev(dev_id);
- if (dd < 0) {
- error("Unable to open hci%d", dev_id);
- return -1;
- }
+ if (confirm_reply(adapter, device, TRUE) < 0)
+ return -EIO;
- hci_send_cmd(dd, OGF_LINK_CTL,
- OCF_USER_CONFIRM_REPLY, 6, dba);
-
- hci_close_dev(dd);
-
- debug("auto accept of confirmation");
-
- return device_request_authentication(device,
- AUTH_TYPE_AUTO, 0, NULL);
+ return device_request_authentication(device, AUTH_TYPE_AUTO,
+ 0, NULL);
}
return device_request_authentication(device, AUTH_TYPE_CONFIRM,
passkey, confirm_cb);
+
+fail:
+ return confirm_reply(adapter, device, FALSE);
}
int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
@@ -447,7 +459,7 @@
struct btd_adapter *adapter;
struct btd_device *device;
- debug("hcid_dbus_bonding_process_complete: status=%02x", status);
+ DBG("status=%02x", status);
if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
return;
@@ -456,7 +468,7 @@
/* This means that there was no pending PIN or SSP token
* request from the controller, i.e. this is not a new
* pairing */
- debug("hcid_dbus_bonding_process_complete: no pending auth request");
+ DBG("no pending auth request");
return;
}
@@ -466,12 +478,12 @@
}
void hcid_dbus_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
- uint8_t status)
+ uint8_t status)
{
struct btd_adapter *adapter;
struct btd_device *device;
- debug("hcid_dbus_simple_pairing_complete: status=%02x", status);
+ DBG("status=%02x", status);
if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
return;
@@ -510,6 +522,7 @@
name_status_t name_status;
int state;
dbus_bool_t legacy;
+ unsigned char features[8];
ba2str(local, local_addr);
ba2str(peer, peer_addr);
@@ -535,8 +548,6 @@
adapter_set_state(adapter, state);
}
- legacy = (data == NULL);
-
memset(&match, 0, sizeof(struct remote_dev_info));
bacpy(&match.bdaddr, peer);
match.name_status = NAME_SENT;
@@ -544,7 +555,7 @@
dev = adapter_search_found_devices(adapter, &match);
if (dev) {
adapter_update_found_devices(adapter, peer, rssi, class,
- NULL, NULL, legacy,
+ NULL, NULL, dev->legacy,
NAME_NOT_REQUIRED);
return;
}
@@ -561,6 +572,18 @@
create_name(filename, PATH_MAX, STORAGEDIR, local_addr, "names");
name = textfile_get(filename, peer_addr);
+ if (data)
+ legacy = FALSE;
+ else if (name == NULL)
+ legacy = TRUE;
+ else if (read_remote_features(local, peer, NULL, features) == 0) {
+ if (features[0] & 0x01)
+ legacy = FALSE;
+ else
+ legacy = TRUE;
+ } else
+ legacy = TRUE;
+
tmp_name = extract_eir_name(data, &name_type);
if (tmp_name) {
if (name_type == 0x09) {
@@ -579,7 +602,6 @@
}
}
-
if (name && name_type != 0x08)
name_status = NAME_SENT;
@@ -591,6 +613,27 @@
g_free(alias);
}
+void hcid_dbus_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer,
+ gboolean legacy)
+{
+ struct btd_adapter *adapter;
+ struct btd_device *device;
+ struct remote_dev_info *dev, match;
+
+ if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) {
+ error("No matching adapter found");
+ return;
+ }
+
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, peer);
+ match.name_status = NAME_ANY;
+
+ dev = adapter_search_found_devices(adapter, &match);
+ if (dev)
+ dev->legacy = legacy;
+}
+
void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
{
uint32_t old_class = 0;
@@ -667,24 +710,47 @@
struct btd_device *device;
struct btd_adapter *adapter;
uint8_t local_auth = 0xff, remote_auth, new_key_type;
- gboolean bonding;
+ gboolean bonding, temporary = FALSE;
if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
return -ENODEV;
- if (key_type == 0x06 && old_key_type != 0xff)
- new_key_type = old_key_type;
- else
- new_key_type = key_type;
+ new_key_type = key_type;
+
+ if (key_type == 0x06) {
+ if (device_get_debug_key(device, NULL))
+ old_key_type = 0x03;
+ if (old_key_type != 0xff)
+ new_key_type = old_key_type;
+ else
+ /* This is Changed Combination Link Key for
+ * a temporary link key.*/
+ return 0;
+ }
get_auth_requirements(local, peer, &local_auth);
remote_auth = device_get_auth(device);
bonding = device_is_bonding(device, NULL);
- debug("local auth 0x%02x and remote auth 0x%02x",
+ DBG("key type 0x%02x old key type 0x%02x new key type 0x%02x",
+ key_type, old_key_type, new_key_type);
+
+ DBG("local auth 0x%02x and remote auth 0x%02x",
local_auth, remote_auth);
- /* Only store the link key if one of the following is true:
+ /* Clear any previous debug key */
+ device_set_debug_key(device, NULL);
+
+ /* If this is not the first link key set a flag so a subsequent auth
+ * complete event doesn't trigger SDP and remove any stored key */
+ if (old_key_type != 0xff) {
+ device_set_renewed_key(device, TRUE);
+ device_remove_bonding(device);
+ }
+
+ /* Store the link key only in runtime memory if it's a debug
+ * key, else 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
@@ -692,14 +758,20 @@
* 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 < 0x03 || (key_type == 0x06 && old_key_type != 0xff) ||
+ if (new_key_type == 0x03) {
+ DBG("Storing debug key in runtime memory");
+ device_set_debug_key(device, key);
+ } else if (key_type < 0x03 ||
+ (key_type == 0x06 && old_key_type != 0xff) ||
(local_auth > 0x01 && remote_auth > 0x01) ||
(local_auth == 0x02 || local_auth == 0x03) ||
(remote_auth == 0x02 || remote_auth == 0x03)) {
int err;
- debug("storing link key of type 0x%02x", key_type);
+ DBG("storing link key of type 0x%02x", key_type);
err = write_link_key(local, peer, key, new_key_type,
pin_length);
@@ -707,18 +779,16 @@
error("write_link_key: %s (%d)", strerror(-err), -err);
return err;
}
- }
-
- /* If this is not the first link key set a flag so a subsequent auth
- * complete event doesn't trigger SDP */
- if (old_key_type != 0xff)
- device_set_renewed_key(device, TRUE);
+ } else
+ temporary = TRUE;
if (!device_is_connected(device))
device_set_secmode3_conn(device, TRUE);
else if (!bonding && old_key_type == 0xff)
hcid_dbus_bonding_process_complete(local, peer, 0);
+ device_set_temporary(device, temporary);
+
return 0;
}
@@ -732,11 +802,15 @@
return;
if (status) {
+ gboolean secmode3 = device_get_secmode3_conn(device);
+
device_set_secmode3_conn(device, FALSE);
+
if (device_is_bonding(device, NULL))
device_bonding_complete(device, status);
if (device_is_temporary(device))
- adapter_remove_device(connection, adapter, device);
+ adapter_remove_device(connection, adapter, device,
+ secmode3);
return;
}
@@ -763,7 +837,7 @@
device = adapter_find_connection(adapter, handle);
if (!device) {
- error("No matching connection found for handle %u", handle);
+ DBG("No matching connection found for handle %u", handle);
return;
}
@@ -823,39 +897,6 @@
hci_close_dev(dd);
}
-void hcid_dbus_write_class_complete(bdaddr_t *local)
-{
- struct btd_adapter *adapter;
- int dd;
- uint8_t cls[3];
- uint16_t dev_id;
-
- adapter = manager_find_adapter(local);
- if (!adapter) {
- error("No matching adapter found");
- return;
- }
-
- dev_id = adapter_get_dev_id(adapter);
-
- dd = hci_open_dev(dev_id);
- if (dd < 0) {
- error("HCI device open failed: hci%d", dev_id);
- return;
- }
-
- if (hci_read_class_of_dev(dd, cls, HCI_REQ_TIMEOUT) < 0) {
- error("Can't read class of device on hci%d: %s (%d)",
- dev_id, strerror(errno), errno);
- hci_close_dev(dd);
- return;
- }
-
- hci_close_dev(dd);
-
- adapter_set_class(adapter, cls);
-}
-
void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local)
{
struct btd_adapter *adapter;
@@ -892,12 +933,24 @@
adapter_update_ssp_mode(adapter, mode);
}
+void hcid_dbus_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);
+}
+
int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
uint8_t *cap, uint8_t *auth)
{
struct btd_adapter *adapter;
struct btd_device *device;
struct agent *agent = NULL;
+ uint8_t agent_cap;
if (!get_adapter_and_device(local, remote, &adapter, &device, TRUE))
return -ENODEV;
@@ -905,7 +958,7 @@
if (get_auth_requirements(local, remote, auth) < 0)
return -1;
- debug("initial authentication requirement is 0x%02x", *auth);
+ DBG("initial authentication requirement is 0x%02x", *auth);
if (*auth == 0xff)
*auth = device_get_auth(device);
@@ -914,10 +967,14 @@
* in progress */
if (!adapter_is_pairable(adapter) &&
!device_is_bonding(device, NULL)) {
- if (*auth < 0x02 && device_get_auth(device) < 0x02) {
- debug("Allowing no bonding in non-bondable mode");
+ if (device_get_auth(device) < 0x02) {
+ DBG("Allowing no bonding in non-bondable mode");
/* No input, no output */
*cap = 0x03;
+ /* Kernel defaults to general bonding and so
+ * overwrite for this special case. Otherwise
+ * non-pairable test cases will fail. */
+ *auth = 0x00;
goto done;
}
return -EPERM;
@@ -925,21 +982,21 @@
/* For CreatePairedDevice use dedicated bonding */
agent = device_get_agent(device);
- if (!agent)
- agent = adapter_get_agent(adapter);
-
if (!agent) {
/* This is the non bondable mode case */
if (device_get_auth(device) > 0x01) {
- debug("Bonding request, but no agent present");
+ DBG("Bonding request, but no agent present");
return -1;
}
/* No agent available, and no bonding case */
- if (*auth == 0x00) {
- debug("Allowing no bonding without agent");
+ if (*auth == 0x00 || *auth == 0x04) {
+ DBG("Allowing no bonding without agent");
/* No input, no output */
*cap = 0x03;
+ /* If kernel defaults to general bonding, set it
+ * back to no bonding */
+ *auth = 0x00;
goto done;
}
@@ -947,11 +1004,12 @@
return -1;
}
- if (*auth == 0x00) {
+ agent_cap = agent_get_io_capability(agent);
+
+ if (*auth == 0x00 || *auth == 0x04) {
/* If remote requests dedicated bonding follow that lead */
if (device_get_auth(device) == 0x02 ||
device_get_auth(device) == 0x03) {
- uint8_t agent_cap = agent_get_io_capability(agent);
/* If both remote and local IO capabilities allow MITM
* then require it, otherwise don't */
@@ -962,16 +1020,26 @@
*auth = 0x03;
}
- /* If remote requires MITM then also require it */
+ /* If remote indicates no bonding then follow that. This
+ * is important since the kernel might give general bonding
+ * as default. */
+ if (device_get_auth(device) == 0x00 ||
+ device_get_auth(device) == 0x01)
+ *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 (device_get_auth(device) != 0xff &&
- (device_get_auth(device) & 0x01))
+ (device_get_auth(device) & 0x01) &&
+ agent_cap != 0x03)
*auth |= 0x01;
}
*cap = agent_get_io_capability(agent);
done:
- debug("final authentication requirement is 0x%02x", *auth);
+ DBG("final authentication requirement is 0x%02x", *auth);
return 0;
}
diff --git a/src/dbus-hci.h b/src/dbus-hci.h
index 382e59e..44cd5e5 100644
--- a/src/dbus-hci.h
+++ b/src/dbus-hci.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -24,6 +24,7 @@
int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci);
void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, int8_t rssi, uint8_t *data);
+void hcid_dbus_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy);
void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class);
void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name);
void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, bdaddr_t *peer);
@@ -31,8 +32,8 @@
void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
void hcid_dbus_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
void hcid_dbus_setscan_enable_complete(bdaddr_t *local);
-void hcid_dbus_write_class_complete(bdaddr_t *local);
void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local);
+void hcid_dbus_returned_link_key(bdaddr_t *local, bdaddr_t *peer);
int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
uint8_t *cap, uint8_t *auth);
int hcid_dbus_set_io_cap(bdaddr_t *local, bdaddr_t *remote,
@@ -44,7 +45,10 @@
uint8_t *key, uint8_t key_type,
int pin_length, uint8_t old_key_type);
-DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status);
+gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
+ struct btd_adapter **adapter,
+ struct btd_device **device,
+ gboolean create);
const char *class_to_icon(uint32_t class);
diff --git a/src/device.c b/src/device.c
index 5328db9..9d50ad9 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <sys/ioctl.h>
#include <errno.h>
#include <bluetooth/bluetooth.h>
@@ -44,7 +45,7 @@
#include <dbus/dbus.h>
#include <gdbus.h>
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "hcid.h"
@@ -80,7 +81,6 @@
DBusConnection *conn;
DBusMessage *msg;
GIOChannel *io;
- guint io_id;
guint listener_id;
struct btd_device *device;
};
@@ -110,6 +110,7 @@
bdaddr_t bdaddr;
gchar *path;
char name[MAX_NAME_LENGTH + 1];
+ char *alias;
struct btd_adapter *adapter;
GSList *uuids;
GSList *drivers; /* List of driver_data */
@@ -134,10 +135,16 @@
sdp_list_t *tmp_records;
+ gboolean trusted;
+ gboolean paired;
+ gboolean blocked;
gboolean renewed_key;
gboolean authorizing;
gint ref;
+
+ gboolean has_debug_key;
+ uint8_t debug_key[16];
};
static uint16_t uuid_list[] = {
@@ -149,14 +156,6 @@
static GSList *device_drivers = NULL;
-static DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn,
- DBusMessage *msg, int err)
-{
- return error_common_reply(conn, msg,
- ERROR_INTERFACE ".ConnectionAttemptFailed",
- err > 0 ? strerror(err) : "Connection attempt failed");
-}
-
static DBusHandlerResult error_failed(DBusConnection *conn,
DBusMessage *msg, const char * desc)
{
@@ -190,6 +189,8 @@
dbus_message_unref(req->msg);
if (req->conn)
dbus_connection_unref(req->conn);
+ if (req->device)
+ btd_device_unref(req->device);
g_slist_foreach(req->profiles_added, (GFunc) g_free, NULL);
g_slist_free(req->profiles_added);
g_slist_free(req->profiles_removed);
@@ -211,8 +212,8 @@
bt_cancel_discovery(&src, &device->bdaddr);
- browse_request_free(req);
device->browse = NULL;
+ browse_request_free(req);
}
static void device_free(gpointer user_data)
@@ -222,7 +223,7 @@
struct agent *agent = adapter_get_agent(adapter);
if (device->agent)
- agent_destroy(device->agent, FALSE);
+ agent_free(device->agent);
if (agent && (agent_is_busy(agent, device) ||
agent_is_busy(agent, device->authr)))
@@ -231,35 +232,32 @@
g_slist_foreach(device->uuids, (GFunc) g_free, NULL);
g_slist_free(device->uuids);
+ if (device->tmp_records)
+ sdp_list_free(device->tmp_records,
+ (sdp_free_func_t) sdp_record_free);
+
if (device->disconn_timer)
g_source_remove(device->disconn_timer);
- debug("device_free(%p)", device);
+ if (device->discov_timer)
+ g_source_remove(device->discov_timer);
+
+ DBG("%p", device);
g_free(device->authr);
g_free(device->path);
+ g_free(device->alias);
g_free(device);
}
gboolean device_is_paired(struct btd_device *device)
{
- struct btd_adapter *adapter = device->adapter;
- char filename[PATH_MAX + 1], *str;
- char srcaddr[18], dstaddr[18];
- gboolean ret;
- bdaddr_t src;
+ return device->paired;
+}
- adapter_get_address(adapter, &src);
- ba2str(&src, srcaddr);
- ba2str(&device->bdaddr, dstaddr);
-
- create_name(filename, PATH_MAX, STORAGEDIR,
- srcaddr, "linkkeys");
- str = textfile_caseget(filename, dstaddr);
- ret = str ? TRUE : FALSE;
- g_free(str);
-
- return ret;
+gboolean device_is_trusted(struct btd_device *device)
+{
+ return device->trusted;
}
static DBusMessage *get_properties(DBusConnection *conn,
@@ -306,13 +304,12 @@
dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ptr);
/* Alias (fallback to name or address) */
- if (read_device_alias(srcaddr, dstaddr, name, sizeof(name)) < 1) {
- if (strlen(ptr) == 0) {
- g_strdelimit(dstaddr, ":", '-');
- ptr = dstaddr;
- }
- } else
- ptr = name;
+ if (device->alias != NULL)
+ ptr = device->alias;
+ else if (strlen(ptr) == 0) {
+ g_strdelimit(dstaddr, ":", '-');
+ ptr = dstaddr;
+ }
dict_append_entry(&dict, "Alias", DBUS_TYPE_STRING, &ptr);
@@ -332,9 +329,13 @@
dict_append_entry(&dict, "Paired", DBUS_TYPE_BOOLEAN, &boolean);
/* Trusted */
- boolean = read_trust(&src, dstaddr, GLOBAL_TRUST);
+ boolean = device_is_trusted(device);
dict_append_entry(&dict, "Trusted", DBUS_TYPE_BOOLEAN, &boolean);
+ /* Blocked */
+ boolean = device->blocked;
+ dict_append_entry(&dict, "Blocked", DBUS_TYPE_BOOLEAN, &boolean);
+
/* Connected */
boolean = (device->handle != 0);
dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN,
@@ -365,6 +366,11 @@
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);
@@ -377,6 +383,9 @@
ERROR_INTERFACE ".Failed",
strerror(-err));
+ g_free(device->alias);
+ device->alias = g_str_equal(alias, "") ? NULL : g_strdup(alias);
+
emit_property_changed(conn, dbus_message_get_path(msg),
DEVICE_INTERFACE, "Alias",
DBUS_TYPE_STRING, &alias);
@@ -385,18 +394,28 @@
}
static DBusMessage *set_trust(DBusConnection *conn, DBusMessage *msg,
- dbus_bool_t value, void *data)
+ gboolean value, void *data)
{
struct btd_device *device = data;
struct btd_adapter *adapter = device->adapter;
char srcaddr[18], dstaddr[18];
bdaddr_t src;
+ int err;
+
+ if (device->trusted == value)
+ return dbus_message_new_method_return(msg);
adapter_get_address(adapter, &src);
ba2str(&src, srcaddr);
ba2str(&device->bdaddr, dstaddr);
- write_trust(srcaddr, dstaddr, GLOBAL_TRUST, value);
+ err = write_trust(srcaddr, dstaddr, GLOBAL_TRUST, value);
+ if (err < 0)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ strerror(-err));
+
+ device->trusted = value;
emit_property_changed(conn, dbus_message_get_path(msg),
DEVICE_INTERFACE, "Trusted",
@@ -405,11 +424,155 @@
return dbus_message_new_method_return(msg);
}
+static void driver_remove(struct btd_driver_data *driver_data,
+ struct btd_device *device)
+{
+ struct btd_device_driver *driver = driver_data->driver;
+
+ driver->remove(device);
+
+ device->drivers = g_slist_remove(device->drivers, driver_data);
+ g_free(driver_data);
+}
+
+static gboolean do_disconnect(gpointer user_data)
+{
+ struct btd_device *device = user_data;
+ disconnect_cp cp;
+ int dd;
+ uint16_t dev_id = adapter_get_dev_id(device->adapter);
+
+ device->disconn_timer = 0;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0)
+ goto fail;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = htobs(device->handle);
+ cp.reason = HCI_OE_USER_ENDED_CONNECTION;
+
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_DISCONNECT,
+ DISCONNECT_CP_SIZE, &cp);
+
+ close(dd);
+
+fail:
+ return FALSE;
+}
+
+static int device_block(DBusConnection *conn, struct btd_device *device)
+{
+ int dev_id, dd, err;
+ bdaddr_t src;
+
+ if (device->blocked)
+ return 0;
+
+ dev_id = adapter_get_dev_id(device->adapter);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0)
+ return -errno;
+
+ if (device->handle)
+ do_disconnect(device);
+
+ g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
+
+ if (ioctl(dd, HCIBLOCKADDR, &device->bdaddr) < 0) {
+ err = -errno;
+ hci_close_dev(dd);
+ return err;
+ }
+
+ hci_close_dev(dd);
+
+ device->blocked = TRUE;
+
+ adapter_get_address(device->adapter, &src);
+
+ err = write_blocked(&src, &device->bdaddr, TRUE);
+ if (err < 0)
+ error("write_blocked(): %s (%d)", strerror(-err), -err);
+
+ device_set_temporary(device, FALSE);
+
+ emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked",
+ DBUS_TYPE_BOOLEAN, &device->blocked);
+
+ return 0;
+}
+
+static int device_unblock(DBusConnection *conn, struct btd_device *device,
+ gboolean silent)
+{
+ int dev_id, dd, err;
+ bdaddr_t src;
+
+ if (!device->blocked)
+ return 0;
+
+ dev_id = adapter_get_dev_id(device->adapter);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0)
+ return -errno;
+
+ if (ioctl(dd, HCIUNBLOCKADDR, &device->bdaddr) < 0) {
+ err = -errno;
+ hci_close_dev(dd);
+ return err;
+ }
+
+ hci_close_dev(dd);
+
+ device->blocked = FALSE;
+
+ adapter_get_address(device->adapter, &src);
+
+ err = write_blocked(&src, &device->bdaddr, FALSE);
+ if (err < 0)
+ error("write_blocked(): %s (%d)", strerror(-err), -err);
+
+ if (!silent) {
+ emit_property_changed(conn, device->path,
+ DEVICE_INTERFACE, "Blocked",
+ DBUS_TYPE_BOOLEAN, &device->blocked);
+ device_probe_drivers(device, device->uuids);
+ }
+
+ return 0;
+}
+
+static DBusMessage *set_blocked(DBusConnection *conn, DBusMessage *msg,
+ gboolean value, void *data)
+{
+ struct btd_device *device = data;
+ int err;
+
+ if (value)
+ err = device_block(conn, device);
+ else
+ err = device_unblock(conn, device, FALSE);
+
+ switch (-err) {
+ case 0:
+ return dbus_message_new_method_return(msg);
+ case EINVAL:
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotSupported",
+ "Kernel lacks blacklist support");
+ default:
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", strerror(-err));
+ }
+}
+
static inline DBusMessage *invalid_args(DBusMessage *msg)
{
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments in method call");
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
}
static DBusMessage *set_property(DBusConnection *conn,
@@ -434,7 +597,6 @@
if (g_str_equal("Trusted", property)) {
dbus_bool_t value;
-
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
return invalid_args(msg);
dbus_message_iter_get_basic(&sub, &value);
@@ -448,6 +610,15 @@
dbus_message_iter_get_basic(&sub, &alias);
return set_alias(conn, msg, alias, data);
+ } else if (g_str_equal("Blocked", property)) {
+ dbus_bool_t value;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
+ return invalid_args(msg);
+
+ dbus_message_iter_get_basic(&sub, &value);
+
+ return set_blocked(conn, msg, value, data);
}
return invalid_args(msg);
@@ -457,7 +628,7 @@
{
struct browse_req *req = user_data;
- debug("DiscoverServices requestor exited");
+ DBG("DiscoverServices requestor exited");
browse_request_cancel(req);
}
@@ -612,42 +783,11 @@
return dbus_message_new_method_return(msg);
}
-static gboolean do_disconnect(gpointer user_data)
-{
- struct btd_device *device = user_data;
- disconnect_cp cp;
- int dd;
- uint16_t dev_id = adapter_get_dev_id(device->adapter);
-
- device->disconn_timer = 0;
-
- dd = hci_open_dev(dev_id);
- if (dd < 0)
- goto fail;
-
- memset(&cp, 0, sizeof(cp));
- cp.handle = htobs(device->handle);
- cp.reason = HCI_OE_USER_ENDED_CONNECTION;
-
- hci_send_cmd(dd, OGF_LINK_CTL, OCF_DISCONNECT,
- DISCONNECT_CP_SIZE, &cp);
-
- close(dd);
-
-fail:
- return FALSE;
-}
-
static void bonding_request_cancel(struct bonding_req *bonding)
{
if (!bonding->io)
return;
- if (bonding->io_id) {
- g_source_remove(bonding->io_id);
- bonding->io_id = 0;
- }
-
g_io_channel_shutdown(bonding->io, TRUE, NULL);
g_io_channel_unref(bonding->io);
bonding->io = NULL;
@@ -842,6 +982,11 @@
device->handle = 0;
+ if (device->disconn_timer > 0) {
+ g_source_remove(device->disconn_timer);
+ device->disconn_timer = 0;
+ }
+
while (device->disconnects) {
DBusMessage *msg = device->disconnects->data;
@@ -898,6 +1043,11 @@
}
}
+gboolean device_get_secmode3_conn(struct btd_device *device)
+{
+ return device->secmode3;
+}
+
void device_set_secmode3_conn(struct btd_device *device, gboolean enable)
{
device->secmode3 = enable;
@@ -911,7 +1061,7 @@
struct btd_device *device;
const gchar *adapter_path = adapter_get_path(adapter);
bdaddr_t src;
- char srcaddr[18];
+ char srcaddr[18], alias[MAX_NAME_LENGTH + 1];
device = g_try_malloc0(sizeof(struct btd_device));
if (device == NULL)
@@ -922,7 +1072,7 @@
g_strdelimit(device->path, ":", '_');
g_free(address_up);
- debug("Creating device %s", device->path);
+ DBG("Creating device %s", device->path);
if (g_dbus_register_interface(conn, device->path, DEVICE_INTERFACE,
device_methods, device_signals, NULL,
@@ -936,18 +1086,24 @@
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);
device->auth = 0xff;
+ if (read_link_key(&src, &device->bdaddr, NULL, NULL) == 0)
+ device->paired = TRUE;
+
return btd_device_ref(device);
}
void device_set_name(struct btd_device *device, const char *name)
{
DBusConnection *conn = get_dbus_connection();
- char alias[MAX_NAME_LENGTH + 1];
- char srcaddr[18], dstaddr[18];
- bdaddr_t src;
if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0)
return;
@@ -958,11 +1114,7 @@
DEVICE_INTERFACE, "Name",
DBUS_TYPE_STRING, &name);
- adapter_get_address(device->adapter, &src);
- ba2str(&src, srcaddr);
- ba2str(&device->bdaddr, dstaddr);
-
- if (read_device_alias(srcaddr, dstaddr, alias, sizeof(alias)) == 0)
+ if (device->alias != NULL)
return;
emit_property_changed(conn, device->path,
@@ -970,14 +1122,17 @@
DBUS_TYPE_STRING, &name);
}
-static void device_remove_bonding(struct btd_device *device,
- DBusConnection *conn)
+void device_get_name(struct btd_device *device, char *name, size_t len)
+{
+ strncpy(name, device->name, len);
+}
+
+void device_remove_bonding(struct btd_device *device)
{
char filename[PATH_MAX + 1];
- char *str, srcaddr[18], dstaddr[18];
+ char srcaddr[18], dstaddr[18];
int dd, dev_id;
bdaddr_t bdaddr;
- gboolean paired;
adapter_get_address(device->adapter, &bdaddr);
ba2str(&bdaddr, srcaddr);
@@ -986,13 +1141,8 @@
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr,
"linkkeys");
- /* textfile_del doesn't return an error when the key is not found */
- str = textfile_caseget(filename, dstaddr);
- paired = str ? TRUE : FALSE;
- g_free(str);
-
- if (!paired)
- return;
+ /* Delete the link key from storage */
+ textfile_casedel(filename, dstaddr);
dev_id = adapter_get_dev_id(device->adapter);
@@ -1000,41 +1150,38 @@
if (dd < 0)
return;
- /* Delete the link key from storage */
- textfile_casedel(filename, dstaddr);
-
/* Delete the link key from the Bluetooth chip */
hci_delete_stored_link_key(dd, &device->bdaddr, 0, HCI_REQ_TIMEOUT);
hci_close_dev(dd);
-
- paired = FALSE;
- emit_property_changed(conn, device->path, DEVICE_INTERFACE,
- "Paired", DBUS_TYPE_BOOLEAN, &paired);
}
-static void device_remove_stored(struct btd_device *device,
- DBusConnection *conn)
+static void device_remove_stored(struct btd_device *device)
{
bdaddr_t src;
char addr[18];
+ DBusConnection *conn = get_dbus_connection();
adapter_get_address(device->adapter, &src);
ba2str(&device->bdaddr, addr);
- device_remove_bonding(device, conn);
+ if (device->paired)
+ device_remove_bonding(device);
delete_entry(&src, "profiles", addr);
delete_entry(&src, "trusts", addr);
delete_all_records(&src, &device->bdaddr);
+
+ if (device->blocked)
+ device_unblock(conn, device, TRUE);
}
-void device_remove(struct btd_device *device, DBusConnection *conn,
- gboolean remove_stored)
+void device_remove(struct btd_device *device, gboolean remove_stored)
{
- GSList *list;
- struct btd_device_driver *driver;
- debug("Removing device %s", device->path);
+ DBG("Removing device %s", device->path);
+
+ if (device->agent)
+ agent_free(device->agent);
if (device->bonding)
device_cancel_bonding(device, HCI_OE_USER_ENDED_CONNECTION);
@@ -1046,15 +1193,11 @@
do_disconnect(device);
if (remove_stored)
- device_remove_stored(device, conn);
+ device_remove_stored(device);
- for (list = device->drivers; list; list = list->next) {
- struct btd_driver_data *driver_data = list->data;
- driver = driver_data->driver;
-
- driver->remove(device);
- g_free(driver_data);
- }
+ g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
+ g_slist_free(device->drivers);
+ device->drivers = NULL;
btd_device_unref(device);
}
@@ -1149,7 +1292,12 @@
GSList *list;
int err;
- debug("Probe drivers for %s", device->path);
+ if (device->blocked) {
+ DBG("Skipping drivers for blocked device %s", device->path);
+ goto add_uuids;
+ }
+
+ DBG("Probe drivers for %s", device->path);
for (list = device_drivers; list; list = list->next) {
struct btd_device_driver *driver = list->data;
@@ -1178,6 +1326,7 @@
g_slist_free(probe_uuids);
}
+add_uuids:
for (list = profiles; list; list = list->next) {
GSList *l = g_slist_find_custom(device->uuids, list->data,
(GCompareFunc) strcasecmp);
@@ -1188,12 +1337,6 @@
g_strdup(list->data),
(GCompareFunc) strcasecmp);
}
-
- if (device->tmp_records) {
- sdp_list_free(device->tmp_records,
- (sdp_free_func_t) sdp_record_free);
- device->tmp_records = NULL;
- }
}
static void device_remove_drivers(struct btd_device *device, GSList *uuids)
@@ -1210,7 +1353,7 @@
records = read_records(&src, &device->bdaddr);
- debug("Remove drivers for %s", device->path);
+ DBG("Remove drivers for %s", device->path);
for (list = device->drivers; list; list = next) {
struct btd_driver_data *driver_data = list->data;
@@ -1221,10 +1364,10 @@
for (uuid = driver->uuids; *uuid; uuid++) {
if (!g_slist_find_custom(uuids, *uuid,
- (GCompareFunc) strcasecmp))
+ (GCompareFunc) strcasecmp))
continue;
- debug("UUID %s was removed from device %s",
+ DBG("UUID %s was removed from device %s",
*uuid, dstaddr);
driver->remove(device);
@@ -1305,6 +1448,12 @@
if (sdp_get_service_classes(rec, &svcclass) < 0)
continue;
+ /* Check for empty service classes list */
+ if (svcclass == NULL) {
+ DBG("Skipping record with no service classes");
+ continue;
+ }
+
/* Extract the first element and skip the remainning */
profile_uuid = bt_uuid2string(svcclass->data);
if (!profile_uuid) {
@@ -1381,30 +1530,43 @@
g_free(str);
}
+static void create_device_reply(struct btd_device *device, struct browse_req *req)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(req->msg);
+ if (!reply)
+ return;
+
+ dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path,
+ DBUS_TYPE_INVALID);
+
+ g_dbus_send_message(req->conn, reply);
+}
+
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;
- DBusMessage *reply;
if (err < 0) {
error("%s: error updating services: %s (%d)",
device->path, strerror(-err), -err);
- goto proceed;
+ goto send_reply;
}
update_services(req, recs);
- if (device->tmp_records && req->records) {
+ if (device->tmp_records)
sdp_list_free(device->tmp_records,
(sdp_free_func_t) sdp_record_free);
- device->tmp_records = req->records;
- req->records = NULL;
- }
+
+ device->tmp_records = req->records;
+ req->records = NULL;
if (!req->profiles_added && !req->profiles_removed) {
- debug("%s: No service update", device->path);
- goto proceed;
+ DBG("%s: No service update", device->path);
+ goto send_reply;
}
/* Probe matching drivers for services added */
@@ -1418,34 +1580,32 @@
/* Propagate services changes */
services_changed(req->device);
-proceed:
- /* Store the device's profiles in the filesystem */
- store_profiles(device);
-
+send_reply:
if (!req->msg)
goto cleanup;
if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
- "DiscoverServices")) {
- discover_services_reply(req, err, req->records);
- goto cleanup;
+ "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) {
+ error_failed_errno(req->conn, req->msg, -err);
+ goto cleanup;
+ }
+
+ create_device_reply(device, req);
+ device_set_temporary(device, FALSE);
}
- /* Reply create device request */
- reply = dbus_message_new_method_return(req->msg);
- if (!reply)
- goto cleanup;
-
- dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path,
- DBUS_TYPE_INVALID);
-
- g_dbus_send_message(req->conn, reply);
-
- device_set_temporary(device, FALSE);
-
cleanup:
- browse_request_free(req);
+ if (!device->temporary)
+ store_profiles(device);
device->browse = NULL;
+ browse_request_free(req);
}
static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
@@ -1519,7 +1679,7 @@
conn = get_dbus_connection();
req->conn = dbus_connection_ref(conn);
- req->device = device;
+ req->device = btd_device_ref(device);
if (search) {
memcpy(&uuid, search, sizeof(uuid_t));
@@ -1547,8 +1707,8 @@
err = bt_search_service(&src, &device->bdaddr,
&uuid, cb, req, NULL);
if (err < 0) {
- browse_request_free(req);
device->browse = NULL;
+ browse_request_free(req);
}
return err;
@@ -1580,15 +1740,10 @@
if (!device)
return NULL;
- return device->agent;
-}
+ if (device->agent)
+ return device->agent;
-void device_set_agent(struct btd_device *device, struct agent *agent)
-{
- if (!device)
- return;
-
- device->agent = agent;
+ return adapter_get_agent(device->adapter);
}
gboolean device_is_busy(struct btd_device *device)
@@ -1646,7 +1801,7 @@
return FALSE;
}
-DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)
+static DBusMessage *new_authentication_return(DBusMessage *msg, int status)
{
switch (status) {
case 0x00: /* success */
@@ -1717,9 +1872,6 @@
if (bonding->conn)
dbus_connection_unref(bonding->conn);
- if (bonding->io_id)
- g_source_remove(bonding->io_id);
-
if (bonding->io)
g_io_channel_unref(bonding->io);
@@ -1734,14 +1886,20 @@
if (!device->agent)
return;
- agent_destroy(device->agent, FALSE);
+ agent_cancel(device->agent);
+ agent_free(device->agent);
device->agent = NULL;
}
-static void device_set_paired(struct btd_device *device, gboolean value)
+void device_set_paired(struct btd_device *device, gboolean value)
{
DBusConnection *conn = get_dbus_connection();
+ if (device->paired == value)
+ return;
+
+ device->paired = value;
+
emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Paired",
DBUS_TYPE_BOOLEAN, &value);
}
@@ -1750,7 +1908,7 @@
{
struct btd_device *device = user_data;
- device_set_agent(device, NULL);
+ device->agent = NULL;
if (device->authr)
device->authr->agent = NULL;
@@ -1766,7 +1924,7 @@
const char *name = dbus_message_get_sender(msg);
struct agent *agent;
- debug("%s: requesting bonding", device->path);
+ DBG("%s: requesting bonding", device->path);
if (!agent_path)
goto proceed;
@@ -1782,7 +1940,7 @@
device->agent = agent;
- debug("Temporary agent registered for %s at %s:%s",
+ DBG("Temporary agent registered for %s at %s:%s",
device->path, name, agent_path);
proceed:
@@ -1794,63 +1952,19 @@
return bonding;
}
-static gboolean bonding_io_cb(GIOChannel *io, GIOCondition cond,
- gpointer user_data)
+static int device_authentication_requested(struct btd_device *device,
+ int handle)
{
- struct btd_device *device = user_data;
- DBusMessage *reply;
-
- if (!device->bonding)
- return FALSE;
-
- reply = new_authentication_return(device->bonding->msg,
- HCI_CONNECTION_TERMINATED);
- g_dbus_send_message(device->bonding->conn, reply);
-
- bonding_request_free(device->bonding);
-
- return FALSE;
-}
-
-static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
- struct btd_device *device = user_data;
struct hci_request rq;
auth_requested_cp cp;
evt_cmd_status rp;
int dd;
- uint16_t handle;
-
- if (!device->bonding) {
- if (!err)
- g_io_channel_shutdown(io, TRUE, NULL);
- return;
- }
-
- if (err) {
- error("%s", err->message);
- error_connection_attempt_failed(device->bonding->conn,
- device->bonding->msg,
- ENETDOWN);
- goto cleanup;
- }
-
- if (!bt_io_get(io, BT_IO_L2RAW, &err,
- BT_IO_OPT_HANDLE, &handle,
- BT_IO_OPT_INVALID)) {
- error("Unable to get connection handle: %s", err->message);
- error_connection_attempt_failed(device->bonding->conn,
- device->bonding->msg,
- ENETDOWN);
- g_error_free(err);
- goto failed;
- }
dd = hci_open_dev(adapter_get_dev_id(device->adapter));
if (dd < 0) {
- DBusMessage *reply = no_such_adapter(device->bonding->msg);
- g_dbus_send_message(device->bonding->conn, reply);
- goto failed;
+ int err = -errno;
+ error("Unable to open adapter: %s(%d)", strerror(-err), -err);
+ return err;
}
memset(&rp, 0, sizeof(rp));
@@ -1868,44 +1982,67 @@
rq.event = EVT_CMD_STATUS;
if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) {
+ int err = -errno;
error("Unable to send HCI request: %s (%d)",
- strerror(errno), errno);
- error_failed_errno(device->bonding->conn, device->bonding->msg,
- errno);
+ strerror(-err), -err);
hci_close_dev(dd);
- goto failed;
+ return err;
}
if (rp.status) {
error("HCI_Authentication_Requested failed with status 0x%02x",
rp.status);
- error_failed_errno(device->bonding->conn, device->bonding->msg,
- bt_error(rp.status));
hci_close_dev(dd);
+ return rp.status;
+ }
+
+ info("Authentication requested");
+
+ hci_close_dev(dd);
+ return 0;
+}
+
+static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+ struct btd_device *device = user_data;
+ uint16_t handle;
+ int status;
+
+ if (!device->bonding) {
+ if (!err)
+ g_io_channel_shutdown(io, TRUE, NULL);
+ return;
+ }
+
+ if (err)
+ /* Wait proper error to be propagated by bonding complete */
+ return;
+
+ if (!bt_io_get(io, BT_IO_L2RAW, &err,
+ BT_IO_OPT_HANDLE, &handle,
+ BT_IO_OPT_INVALID)) {
+ error("Unable to get connection handle: %s", err->message);
+ g_error_free(err);
+ status = -errno;
goto failed;
}
- hci_close_dev(dd);
-
- device->bonding->io_id = g_io_add_watch(io,
- G_IO_NVAL | G_IO_HUP | G_IO_ERR,
- bonding_io_cb, device);
+ status = device_authentication_requested(device, handle);
+ if (status != 0)
+ goto failed;
return;
failed:
g_io_channel_shutdown(io, TRUE, NULL);
-
-cleanup:
- device->bonding->io_id = 0;
- bonding_request_free(device->bonding);
+ device_cancel_bonding(device, status);
}
static void create_bond_req_exit(DBusConnection *conn, void *user_data)
{
struct btd_device *device = user_data;
- debug("%s: requestor exited before bonding was completed", device->path);
+ DBG("%s: requestor exited before bonding was completed", device->path);
if (device->authr)
device_cancel_authentication(device, FALSE);
@@ -1929,6 +2066,7 @@
bdaddr_t src;
GError *err = NULL;
GIOChannel *io;
+ BtIOSecLevel sec_level;
adapter_get_address(adapter, &src);
ba2str(&src, srcaddr);
@@ -1949,12 +2087,19 @@
"Bonding already exists");
}
+ /* If our IO capability is NoInputNoOutput use medium security
+ * level (i.e. don't require MITM protection) else use high
+ * security level */
+ if (capability == 0x03)
+ sec_level = BT_IO_SEC_MEDIUM;
+ else
+ sec_level = BT_IO_SEC_HIGH;
io = bt_io_connect(BT_IO_L2RAW, bonding_connect_cb, device,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &src,
BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
+ BT_IO_OPT_SEC_LEVEL, sec_level,
BT_IO_OPT_INVALID);
if (io == NULL) {
DBusMessage *reply;
@@ -2002,8 +2147,11 @@
if (auth && auth->type == AUTH_TYPE_NOTIFY && auth->agent)
agent_cancel(auth->agent);
- if (status)
- goto failed;
+ if (status) {
+ device_cancel_authentication(device, TRUE);
+ device_cancel_bonding(device, status);
+ return;
+ }
device->auth = 0xff;
@@ -2037,7 +2185,7 @@
/* If we are not initiators and there is no currently
* active discovery or discovery timer, set discovery
* timer */
- debug("setting timer for reverse service discovery");
+ DBG("setting timer for reverse service discovery");
device->discov_timer = g_timeout_add_seconds(
DISCOVERY_TIMER,
start_discovery,
@@ -2046,11 +2194,6 @@
}
device_set_paired(device, TRUE);
-
- return;
-
-failed:
- device_cancel_bonding(device, status);
}
gboolean device_is_creating(struct btd_device *device, const char *sender)
@@ -2097,7 +2240,7 @@
if (!bonding)
return;
- debug("%s: canceling bonding request", device->path);
+ DBG("%s: canceling bonding request", device->path);
if (device->authr)
device_cancel_authentication(device, FALSE);
@@ -2109,19 +2252,20 @@
bonding_request_free(bonding);
}
-static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,
- void *data)
+static void pincode_cb(struct agent *agent, DBusError *err,
+ const char *pincode, void *data)
{
struct authentication_req *auth = data;
struct btd_device *device = auth->device;
/* No need to reply anything if the authentication already failed */
- if (!auth->cb)
+ if (auth->cb == NULL)
return;
((agent_pincode_cb) auth->cb)(agent, err, pincode, device);
- auth->cb = NULL;
+ device->authr->cb = NULL;
+ device->authr->agent = NULL;
}
static void confirm_cb(struct agent *agent, DBusError *err, void *data)
@@ -2130,27 +2274,29 @@
struct btd_device *device = auth->device;
/* No need to reply anything if the authentication already failed */
- if (!auth->cb)
+ if (auth->cb == NULL)
return;
((agent_cb) auth->cb)(agent, err, device);
- auth->cb = NULL;
+ device->authr->cb = NULL;
+ device->authr->agent = NULL;
}
-static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
- void *data)
+static void passkey_cb(struct agent *agent, DBusError *err,
+ uint32_t passkey, void *data)
{
struct authentication_req *auth = data;
struct btd_device *device = auth->device;
/* No need to reply anything if the authentication already failed */
- if (!auth->cb)
+ if (auth->cb == NULL)
return;
((agent_passkey_cb) auth->cb)(agent, err, passkey, device);
- auth->cb = NULL;
+ device->authr->cb = NULL;
+ device->authr->agent = NULL;
}
static void pairing_consent_cb(struct agent *agent, DBusError *err, void *data)
@@ -2168,19 +2314,15 @@
}
int device_request_authentication(struct btd_device *device, auth_type_t type,
- uint32_t passkey, void *cb)
+ uint32_t passkey, void *cb)
{
struct authentication_req *auth;
struct agent *agent;
- int ret;
+ int err;
- debug("%s: requesting agent authentication", device->path);
+ DBG("%s: requesting agent authentication", device->path);
- agent = device->agent;
-
- if (!agent)
- agent = adapter_get_agent(device->adapter);
-
+ agent = device_get_agent(device);
if (!agent) {
error("No agent available for %u request", type);
return -EPERM;
@@ -2195,49 +2337,52 @@
switch (type) {
case AUTH_TYPE_PINCODE:
- ret = agent_request_pincode(agent, device, pincode_cb,
+ err = agent_request_pincode(agent, device, pincode_cb,
auth, NULL);
break;
case AUTH_TYPE_PASSKEY:
- ret = agent_request_passkey(agent, device, passkey_cb,
+ err = agent_request_passkey(agent, device, passkey_cb,
auth, NULL);
break;
case AUTH_TYPE_CONFIRM:
- ret = agent_request_confirmation(agent, device, passkey,
+ err = agent_request_confirmation(agent, device, passkey,
confirm_cb, auth, NULL);
break;
case AUTH_TYPE_NOTIFY:
- ret = agent_display_passkey(agent, device, passkey);
+ err = agent_display_passkey(agent, device, passkey);
break;
case AUTH_TYPE_AUTO:
- ret = 0;
+ err = 0;
break;
case AUTH_TYPE_PAIRING_CONSENT:
- ret = agent_request_pairing_consent(agent, device,
+ err = agent_request_pairing_consent(agent, device,
pairing_consent_cb, auth, NULL);
break;
default:
- ret = -EINVAL;
+ err = -EINVAL;
}
- if (ret < 0) {
+ if (err < 0) {
error("Failed requesting authentication");
g_free(auth);
device->authr = NULL;
}
- return ret;
+ return err;
}
static void cancel_authentication(struct authentication_req *auth)
{
- struct btd_device *device = auth->device;
- struct agent *agent = auth->agent;
+ struct btd_device *device;
+ struct agent *agent;
DBusError err;
- if (!auth->cb)
+ if (!auth || !auth->cb)
return;
+ device = auth->device;
+ agent = auth->agent;
+
dbus_error_init(&err);
dbus_set_error_const(&err, "org.bluez.Error.Canceled", NULL);
@@ -2271,7 +2416,7 @@
if (!auth)
return;
- debug("%s: canceling authentication request", device->path);
+ DBG("%s: canceling authentication request", device->path);
if (auth->agent)
agent_cancel(auth->agent);
@@ -2325,12 +2470,17 @@
}
const sdp_record_t *btd_device_get_record(struct btd_device *device,
- const char *uuid)
+ const char *uuid)
{
bdaddr_t src;
- if (device->tmp_records)
- return find_record_in_list(device->tmp_records, uuid);
+ 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);
@@ -2341,6 +2491,30 @@
return find_record_in_list(device->tmp_records, uuid);
}
+gboolean device_set_debug_key(struct btd_device *device, uint8_t *key)
+{
+ if (key == NULL) {
+ device->has_debug_key = FALSE;
+ return TRUE;
+ }
+
+ memcpy(device->debug_key, key, 16);
+ device->has_debug_key = TRUE;
+
+ return TRUE;
+}
+
+gboolean device_get_debug_key(struct btd_device *device, uint8_t *key)
+{
+ if (!device->has_debug_key)
+ return FALSE;
+
+ if (key != NULL)
+ memcpy(key, device->debug_key, 16);
+
+ return TRUE;
+}
+
int btd_register_device_driver(struct btd_device_driver *driver)
{
device_drivers = g_slist_append(device_drivers, driver);
@@ -2357,7 +2531,7 @@
{
device->ref++;
- debug("btd_device_ref(%p): ref=%d", device, device->ref);
+ DBG("%p: ref=%d", device, device->ref);
return device;
}
@@ -2369,7 +2543,7 @@
device->ref--;
- debug("btd_device_unref(%p): ref=%d", device, device->ref);
+ DBG("%p: ref=%d", device, device->ref);
if (device->ref > 0)
return;
diff --git a/src/device.h b/src/device.h
index c6677dc..752dad3 100644
--- a/src/device.h
+++ b/src/device.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -38,8 +38,8 @@
struct btd_device *device_create(DBusConnection *conn, struct btd_adapter *adapter,
const gchar *address);
void device_set_name(struct btd_device *device, const char *name);
-void device_remove(struct btd_device *device, DBusConnection *conn,
- gboolean remove_stored);
+void device_get_name(struct btd_device *device, char *name, size_t len);
+void device_remove(struct btd_device *device, gboolean remove_stored);
gint device_address_cmp(struct btd_device *device, const gchar *address);
int device_browse(struct btd_device *device, DBusConnection *conn,
DBusMessage *msg, uuid_t *search, gboolean reverse);
@@ -51,21 +51,23 @@
void device_get_address(struct btd_device *adapter, bdaddr_t *bdaddr);
const gchar *device_get_path(struct btd_device *device);
struct agent *device_get_agent(struct btd_device *device);
-void device_set_agent(struct btd_device *device, struct agent *agent);
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_trusted(struct btd_device *device);
+void device_set_paired(struct btd_device *device, gboolean paired);
void device_set_temporary(struct btd_device *device, gboolean temporary);
void device_set_cap(struct btd_device *device, uint8_t cap);
uint8_t device_get_cap(struct btd_device *device);
void device_set_auth(struct btd_device *device, uint8_t auth);
uint8_t device_get_auth(struct btd_device *device);
gboolean device_is_connected(struct btd_device *device);
+gboolean device_get_secmode3_conn(struct btd_device *device);
void device_set_secmode3_conn(struct btd_device *device, gboolean enable);
DBusMessage *device_create_bonding(struct btd_device *device,
DBusConnection *conn, DBusMessage *msg,
const char *agent_path, uint8_t capability);
-void device_remove_bondind(struct btd_device *device, DBusConnection *connection);
+void device_remove_bonding(struct btd_device *device);
void device_bonding_complete(struct btd_device *device, uint8_t status);
void device_simple_pairing_complete(struct btd_device *device, uint8_t status);
gboolean device_is_creating(struct btd_device *device, const char *sender);
@@ -78,6 +80,8 @@
gboolean device_is_authorizing(struct btd_device *device);
void device_set_authorizing(struct btd_device *device, gboolean auth);
void device_set_renewed_key(struct btd_device *device, gboolean renewed);
+gboolean device_set_debug_key(struct btd_device *device, uint8_t *key);
+gboolean device_get_debug_key(struct btd_device *device, uint8_t *key);
void device_add_connection(struct btd_device *device, DBusConnection *conn,
uint16_t handle);
uint16_t device_get_handle(struct btd_device *device);
diff --git a/src/error.c b/src/error.c
index f54e819..c1a2fbf 100644
--- a/src/error.c
+++ b/src/error.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2007-2008 Fabien Chevalier <fabchevalier@free.fr>
*
*
diff --git a/src/error.h b/src/error.h
index 82301d5..49ec05e 100644
--- a/src/error.h
+++ b/src/error.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2007-2008 Fabien Chevalier <fabchevalier@free.fr>
*
*
diff --git a/src/genbuiltin b/src/genbuiltin
new file mode 100755
index 0000000..8b6f047
--- /dev/null
+++ b/src/genbuiltin
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+for i in $*
+do
+ echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$i;"
+done
+
+echo
+echo "static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {"
+
+for i in $*
+do
+ echo " &__bluetooth_builtin_$i,"
+done
+
+echo " NULL"
+echo "};"
diff --git a/common/glib-helper.c b/src/glib-helper.c
similarity index 99%
rename from common/glib-helper.c
rename to src/glib-helper.c
index 727c55d..41f5e3c 100644
--- a/common/glib-helper.c
+++ b/src/glib-helper.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -765,6 +765,7 @@
if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
err = errno;
+ g_free(cmd);
goto failed;
}
diff --git a/common/glib-helper.h b/src/glib-helper.h
similarity index 95%
rename from common/glib-helper.h
rename to src/glib-helper.h
index 751f3a7..1c8e19a 100644
--- a/common/glib-helper.h
+++ b/src/glib-helper.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/hcid.h b/src/hcid.h
index 2f07259..9c5f1d6 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -60,6 +60,7 @@
gboolean remember_powered;
gboolean reverse_sdp;
gboolean name_resolv;
+ gboolean debug_keys;
uint8_t scan;
uint8_t mode;
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..4ec4633
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,136 @@
+/*
+ *
+ * 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 <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 btd_debug(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ vsyslog(LOG_DEBUG, format, ap);
+
+ va_end(ap);
+}
+
+extern struct btd_debug_desc __start___debug[];
+extern struct btd_debug_desc __stop___debug[];
+
+static gchar **enabled = NULL;
+
+static gboolean is_enabled(struct btd_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 __btd_toggle_debug()
+{
+ struct btd_debug_desc *desc;
+
+ for (desc = __start___debug; desc < __stop___debug; desc++)
+ desc->flags |= BTD_DEBUG_FLAG_PRINT;
+}
+
+void __btd_log_init(const char *debug, int detach)
+{
+ int option = LOG_NDELAY | LOG_PID;
+ struct btd_debug_desc *desc;
+ const char *name = NULL, *file = NULL;
+
+ if (debug != NULL)
+ enabled = g_strsplit_set(debug, ":, ", 0);
+
+ for (desc = __start___debug; desc < __stop___debug; desc++) {
+ if (file != NULL || name != NULL) {
+ if (g_strcmp0(desc->file, file) == 0) {
+ if (desc->name == NULL)
+ desc->name = name;
+ } else
+ file = NULL;
+ }
+
+ if (is_enabled(desc))
+ desc->flags |= BTD_DEBUG_FLAG_PRINT;
+ }
+
+ if (!detach)
+ option |= LOG_PERROR;
+
+ openlog("bluetoothd", option, LOG_DAEMON);
+
+ syslog(LOG_INFO, "Bluetooth deamon %s", VERSION);
+}
+
+void __btd_log_cleanup(void)
+{
+ closelog();
+
+ g_strfreev(enabled);
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..cc45cbf
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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
+ *
+ */
+
+void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void btd_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void __btd_log_init(const char *debug, int detach);
+void __btd_log_cleanup(void);
+void __btd_toggle_debug();
+
+struct btd_debug_desc {
+ const char *name;
+ const char *file;
+#define BTD_DEBUG_FLAG_DEFAULT (0)
+#define BTD_DEBUG_FLAG_PRINT (1 << 0)
+ unsigned int flags;
+} __attribute__((aligned(8)));
+
+/**
+ * DBG:
+ * @fmt: format string
+ * @arg...: list of arguments
+ *
+ * Simple macro around btd_debug() which also include the function
+ * name it is called in.
+ */
+#define DBG(fmt, arg...) do { \
+ static struct btd_debug_desc __btd_debug_desc \
+ __attribute__((used, section("__debug"), aligned(8))) = { \
+ .file = __FILE__, .flags = BTD_DEBUG_FLAG_DEFAULT, \
+ }; \
+ if (__btd_debug_desc.flags & BTD_DEBUG_FLAG_PRINT) \
+ btd_debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg); \
+} while (0)
+
diff --git a/src/main.c b/src/main.c
index 8b66127..2402539 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -50,7 +50,7 @@
#include <dbus/dbus.h>
-#include "logging.h"
+#include "log.h"
#include "hcid.h"
#include "sdpd.h"
@@ -60,6 +60,10 @@
#include "agent.h"
#include "manager.h"
+#ifdef HAVE_CAPNG
+#include <cap-ng.h>
+#endif
+
#define LAST_ADAPTER_EXIT_TIMEOUT 30
struct main_opts main_opts;
@@ -93,15 +97,15 @@
if (!config)
return;
- debug("parsing main.conf");
+ DBG("parsing main.conf");
val = g_key_file_get_integer(config, "General",
"DiscoverableTimeout", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else {
- debug("discovto=%d", val);
+ DBG("discovto=%d", val);
main_opts.discovto = val;
main_opts.flags |= 1 << HCID_SET_DISCOVTO;
}
@@ -109,29 +113,29 @@
val = g_key_file_get_integer(config, "General",
"PairableTimeout", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else {
- debug("pairto=%d", val);
+ DBG("pairto=%d", val);
main_opts.pairto = val;
}
val = g_key_file_get_integer(config, "General", "PageTimeout", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else {
- debug("pageto=%d", val);
+ DBG("pageto=%d", val);
main_opts.pageto = val;
main_opts.flags |= 1 << HCID_SET_PAGETO;
}
str = g_key_file_get_string(config, "General", "Name", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else {
- debug("name=%s", str);
+ DBG("name=%s", str);
g_free(main_opts.name);
main_opts.name = g_strdup(str);
main_opts.flags |= 1 << HCID_SET_NAME;
@@ -140,10 +144,10 @@
str = g_key_file_get_string(config, "General", "Class", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else {
- debug("class=%s", str);
+ DBG("class=%s", str);
main_opts.class = strtol(str, NULL, 16);
main_opts.flags |= 1 << HCID_SET_CLASS;
g_free(str);
@@ -152,17 +156,17 @@
val = g_key_file_get_integer(config, "General",
"DiscoverSchedulerInterval", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else {
- debug("discov_interval=%d", val);
+ DBG("discov_interval=%d", val);
main_opts.discov_interval = val;
}
boolean = g_key_file_get_boolean(config, "General",
"InitiallyPowered", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else if (boolean == FALSE)
main_opts.mode = MODE_OFF;
@@ -170,17 +174,17 @@
boolean = g_key_file_get_boolean(config, "General",
"RememberPowered", &err);
if (err) {
- debug("%s", err->message);
+ 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) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else {
- debug("deviceid=%s", str);
+ DBG("deviceid=%s", str);
strncpy(main_opts.deviceid, str,
sizeof(main_opts.deviceid) - 1);
g_free(str);
@@ -189,7 +193,7 @@
boolean = g_key_file_get_boolean(config, "General",
"ReverseServiceDiscovery", &err);
if (err) {
- debug("%s", err->message);
+ DBG("%s", err->message);
g_clear_error(&err);
} else
main_opts.reverse_sdp = boolean;
@@ -201,12 +205,23 @@
else
main_opts.name_resolv = boolean;
+ boolean = g_key_file_get_boolean(config, "General",
+ "DebugKeys", &err);
+ if (err)
+ g_clear_error(&err);
+ else
+ main_opts.debug_keys = boolean;
+
+ main_opts.link_mode = HCI_LM_ACCEPT;
+
+ main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF |
+ HCI_LP_HOLD | HCI_LP_PARK;
str = g_key_file_get_string(config, "General",
"DefaultLinkPolicy", &err);
if (err)
g_clear_error(&err);
else {
- debug("default_link_policy=%s", str);
+ DBG("default_link_policy=%s", str);
main_opts.link_policy &= strtol(str, NULL, 16);
}
}
@@ -318,11 +333,12 @@
static void sig_debug(int sig)
{
- toggle_debug();
+ __btd_toggle_debug();
}
+static gchar *option_debug = NULL;
static gboolean option_detach = TRUE;
-static gboolean option_debug = FALSE;
+static gboolean option_version = FALSE;
static gboolean option_udev = FALSE;
static guint last_adapter_timeout = 0;
@@ -355,12 +371,26 @@
last_adapter_timeout = 0;
}
+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[] = {
- { "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
+ { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+ G_OPTION_ARG_CALLBACK, parse_debug,
+ "Specify debug options to enable", "DEBUG" },
+ { "nodetach", 'n', G_OPTION_FLAG_REVERSE,
G_OPTION_ARG_NONE, &option_detach,
"Don't run as daemon in background" },
- { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
- "Enable debug information output" },
+ { "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 },
@@ -383,6 +413,15 @@
init_defaults();
+#ifdef HAVE_CAPNG
+ /* Drop capabilities */
+ capng_clear(CAPNG_SELECT_BOTH);
+ capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+ CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
+ CAP_NET_RAW, CAP_IPC_LOCK, -1);
+ capng_apply(CAPNG_SELECT_BOTH);
+#endif
+
context = g_option_context_new(NULL);
g_option_context_add_main_entries(context, options, NULL);
@@ -395,6 +434,13 @@
exit(1);
}
+ g_option_context_free(context);
+
+ if (option_version == TRUE) {
+ printf("%s\n", VERSION);
+ exit(0);
+ }
+
if (option_udev == TRUE) {
int err;
@@ -407,8 +453,6 @@
}
}
- g_option_context_free(context);
-
if (option_detach == TRUE && option_udev == FALSE) {
if (daemon(0, 0)) {
perror("Can't start daemon");
@@ -418,7 +462,7 @@
umask(0077);
- start_logging("bluetoothd", "Bluetooth daemon %s", VERSION);
+ __btd_log_init(option_debug, option_detach);
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_NOCLDSTOP;
@@ -432,11 +476,6 @@
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
- if (option_debug == TRUE) {
- info("Enabling debug information");
- enable_debug();
- }
-
config = load_config(CONFIGDIR "/main.conf");
parse_config(config);
@@ -472,7 +511,7 @@
rfkill_init();
- debug("Entering main loop");
+ DBG("Entering main loop");
g_main_loop_run(event_loop);
@@ -495,7 +534,7 @@
info("Exit");
- stop_logging();
+ __btd_log_cleanup();
return 0;
}
diff --git a/src/main.conf b/src/main.conf
index 9174deb..bb401fe 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -51,6 +51,11 @@
# remote devices name and want shorter discovery cycle. Defaults to 'true'.
NameResolving = true
+# Enable runtime persistency of debug link keys. Default is false which
+# makes debug link keys valid only for the duration of the connection
+# that they were created for.
+DebugKeys = false
+
# The link policy for connections. By default it's set to 0x000f which is
# a bitwise OR of role switch(0x0001), hold mode(0x0002), sniff mode(0x0004)
# and park state(0x0008) are all enabled. However, some devices have
diff --git a/src/manager.c b/src/manager.c
index 3cf914d..9b90cab 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -45,7 +45,7 @@
#include "hcid.h"
#include "dbus-common.h"
-#include "logging.h"
+#include "log.h"
#include "adapter.h"
#include "error.h"
#include "manager.h"
@@ -61,32 +61,9 @@
return base_path;
}
-void manager_update_svc(const bdaddr_t *bdaddr, uint8_t svc)
+void manager_update_svc(struct btd_adapter* adapter, uint8_t svc)
{
- GSList *l;
- bdaddr_t src;
-
- for (l = adapters; l != NULL; l = l->next) {
- struct btd_adapter *adapter = l->data;
-
- adapter_get_address(adapter, &src);
-
- if (bacmp(bdaddr, BDADDR_ANY) != 0 && bacmp(bdaddr, &src) != 0)
- continue;
-
- adapter_update(adapter, svc);
- }
-}
-
-int manager_get_adapter_class(uint16_t dev_id, uint8_t *cls)
-{
- struct btd_adapter *adapter;
-
- adapter = manager_find_adapter_by_id(dev_id);
- if (!adapter)
- return -EINVAL;
-
- return adapter_get_class(adapter, cls);
+ adapter_update(adapter, svc);
}
static inline DBusMessage *invalid_args(DBusMessage *msg)
@@ -139,8 +116,8 @@
DBUS_TYPE_INVALID))
return NULL;
- /* hci_devid() would make sense to use here, except it
- is restricted to devices which are up */
+ /* 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)
@@ -240,7 +217,8 @@
{ "GetProperties", "", "a{sv}",get_properties },
{ "DefaultAdapter", "", "o", default_adapter },
{ "FindAdapter", "s", "o", find_adapter },
- { "ListAdapters", "", "ao", list_adapters },
+ { "ListAdapters", "", "ao", list_adapters,
+ G_DBUS_METHOD_FLAG_DEPRECATED},
{ }
};
@@ -259,8 +237,8 @@
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);
+ manager_methods, manager_signals,
+ NULL, NULL, NULL);
}
static void manager_update_adapters(void)
@@ -359,7 +337,7 @@
adapter_get_address(adapter, &bdaddr);
ba2str(&bdaddr, addr);
- return strcmp(addr, address);
+ return strcasecmp(addr, address);
}
struct btd_adapter *manager_find_adapter(const bdaddr_t *sba)
@@ -399,7 +377,8 @@
{
GSList *match;
- match = g_slist_find_custom(adapters, GINT_TO_POINTER(id), adapter_id_cmp);
+ match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
+ adapter_id_cmp);
if (!match)
return NULL;
@@ -414,9 +393,9 @@
void manager_add_adapter(const char *path)
{
g_dbus_emit_signal(connection, "/",
- MANAGER_INTERFACE, "AdapterAdded",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
+ MANAGER_INTERFACE, "AdapterAdded",
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
manager_update_adapters();
@@ -462,7 +441,7 @@
int manager_start_adapter(int id)
{
- struct btd_adapter* adapter;
+ struct btd_adapter *adapter;
int ret;
adapter = manager_find_adapter_by_id(id);
diff --git a/src/manager.h b/src/manager.h
index 9463574..6bf3e76 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -43,6 +43,5 @@
void manager_add_adapter(const char *path);
int manager_get_default_adapter();
void manager_set_default_adapter(int id);
-void manager_update_svc(const bdaddr_t *bdaddr, uint8_t svc);
-int manager_get_adapter_class(uint16_t dev_id, uint8_t *cls);
+void manager_update_svc(struct btd_adapter *adapter, uint8_t svc);
void btd_manager_set_offline(gboolean offline);
diff --git a/common/oui.c b/src/oui.c
similarity index 96%
rename from common/oui.c
rename to src/oui.c
index 9863973..1096d20 100644
--- a/common/oui.c
+++ b/src/oui.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/common/oui.h b/src/oui.h
similarity index 92%
rename from common/oui.h
rename to src/oui.h
index 79aa30b..ad66e56 100644
--- a/common/oui.h
+++ b/src/oui.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/plugin.c b/src/plugin.c
index 706a14f..a63ce8e 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@
#include <glib.h>
#include "plugin.h"
-#include "logging.h"
+#include "log.h"
#include "hcid.h"
#include "btio.h"
@@ -67,7 +67,7 @@
return FALSE;
}
- debug("Loading %s plugin", desc->name);
+ DBG("Loading %s plugin", desc->name);
plugin = g_try_new0(struct bluetooth_plugin, 1);
if (plugin == NULL)
@@ -86,6 +86,9 @@
{
int i;
+ if (list == NULL)
+ return FALSE;
+
for (i = 0; list[i] != NULL; i++) {
char *str;
gboolean equal;
@@ -116,9 +119,6 @@
gchar **disabled;
unsigned int i;
- if (strlen(PLUGINDIR) == 0)
- return FALSE;
-
/* Make a call to BtIO API so its symbols got resolved before the
* plugins are loaded. */
bt_io_error_quark();
@@ -130,22 +130,26 @@
else
disabled = NULL;
- debug("Loading builtin plugins");
+ DBG("Loading builtin plugins");
for (i = 0; __bluetooth_builtin[i]; i++) {
- if (disabled && is_disabled(__bluetooth_builtin[i]->name,
- disabled))
+ if (is_disabled(__bluetooth_builtin[i]->name, disabled))
continue;
add_plugin(NULL, __bluetooth_builtin[i]);
}
- debug("Loading plugins %s", PLUGINDIR);
+ if (strlen(PLUGINDIR) == 0) {
+ g_strfreev(disabled);
+ goto start;
+ }
+
+ DBG("Loading plugins %s", PLUGINDIR);
dir = g_dir_open(PLUGINDIR, 0, NULL);
if (!dir) {
g_strfreev(disabled);
- return FALSE;
+ goto start;
}
while ((file = g_dir_read_name(dir)) != NULL) {
@@ -157,7 +161,7 @@
g_str_has_suffix(file, ".so") == FALSE)
continue;
- if (disabled && is_disabled(file, disabled))
+ if (is_disabled(file, disabled))
continue;
filename = g_build_filename(PLUGINDIR, file, NULL);
@@ -187,11 +191,14 @@
g_strfreev(disabled);
+start:
for (list = plugins; list; list = list->next) {
struct bluetooth_plugin *plugin = list->data;
- if (plugin->desc->init() < 0)
+ if (plugin->desc->init() < 0) {
+ error("Failed to init %s plugin", plugin->desc->name);
continue;
+ }
plugin->active = TRUE;
}
@@ -203,7 +210,7 @@
{
GSList *list;
- debug("Cleanup plugins");
+ DBG("Cleanup plugins");
for (list = plugins; list; list = list->next) {
struct bluetooth_plugin *plugin = list->data;
diff --git a/src/plugin.h b/src/plugin.h
index 00e0b3b..30bd415 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/common/ppoll.h b/src/ppoll.h
similarity index 100%
rename from common/ppoll.h
rename to src/ppoll.h
diff --git a/src/rfkill.c b/src/rfkill.c
index 286fc5c..7810846 100644
--- a/src/rfkill.c
+++ b/src/rfkill.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@
#include <glib.h>
-#include "logging.h"
+#include "log.h"
#include "manager.h"
#include "adapter.h"
#include "hcid.h"
@@ -90,7 +90,7 @@
if (len != sizeof(struct rfkill_event))
return TRUE;
- debug("RFKILL event idx %u type %u op %u soft %u hard %u",
+ DBG("RFKILL event idx %u type %u op %u soft %u hard %u",
event->idx, event->type, event->op,
event->soft, event->hard);
@@ -131,7 +131,7 @@
if (!adapter)
return TRUE;
- debug("RFKILL unblock for hci%d", id);
+ DBG("RFKILL unblock for hci%d", id);
btd_adapter_restore_powered(adapter);
diff --git a/common/sdp-xml.c b/src/sdp-xml.c
similarity index 97%
rename from common/sdp-xml.c
rename to src/sdp-xml.c
index 18473d0..4b0520d 100644
--- a/common/sdp-xml.c
+++ b/src/sdp-xml.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,6 @@
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
-#include "logging.h"
#include "sdp-xml.h"
#define STRBUFSIZE 1024
@@ -675,8 +674,6 @@
ret = sdp_data_alloc_with_length(dtd, url, length);
- debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
-
free(url);
return ret;
@@ -696,8 +693,6 @@
ret = sdp_data_alloc_with_length(dtd, text, length);
- debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
-
free(text);
return ret;
@@ -733,12 +728,8 @@
if (elem->data)
sdp_data_free(elem->data);
- if (elem->name)
- free(elem->name);
-
- if (elem->text)
-
- free(elem->text);
+ free(elem->name);
+ free(elem->text);
free(elem);
}
diff --git a/common/sdp-xml.h b/src/sdp-xml.h
similarity index 96%
rename from common/sdp-xml.h
rename to src/sdp-xml.h
index 191f9df..7031276 100644
--- a/common/sdp-xml.h
+++ b/src/sdp-xml.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sdpd-database.c b/src/sdpd-database.c
index 3ce056a..4c8acb7 100644
--- a/src/sdpd-database.c
+++ b/src/sdpd-database.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -39,7 +39,8 @@
#include <bluetooth/sdp_lib.h>
#include "sdpd.h"
-#include "logging.h"
+#include "log.h"
+#include "adapter.h"
static sdp_list_t *service_db;
static sdp_list_t *access_db;
@@ -54,7 +55,7 @@
* The service repository is a linked list in sorted order
* and the service record handle is the sort key
*/
-static int record_sort(const void *r1, const void *r2)
+int record_sort(const void *r1, const void *r2)
{
const sdp_record_t *rec1 = (const sdp_record_t *) r1;
const sdp_record_t *rec2 = (const sdp_record_t *) r2;
@@ -183,6 +184,8 @@
dev->handle = rec->handle;
access_db = sdp_list_insert_sorted(access_db, dev, access_sort);
+
+ adapter_service_insert(device, rec);
}
static sdp_list_t *record_locate(uint32_t handle)
@@ -252,6 +255,7 @@
if (p) {
a = (sdp_access_t *) p->data;
if (a) {
+ adapter_service_remove(&a->device, r);
access_db = sdp_list_remove(access_db, a);
access_free(a);
}
diff --git a/src/sdpd-request.c b/src/sdpd-request.c
index 1aa0930..d56ffc2 100644
--- a/src/sdpd-request.c
+++ b/src/sdpd-request.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -43,7 +43,7 @@
#include <netinet/in.h>
#include "sdpd.h"
-#include "logging.h"
+#include "log.h"
#define MIN(x, y) ((x) < (y)) ? (x): (y)
@@ -98,7 +98,7 @@
/*
* Generic data element sequence extractor. Builds
- * a list whose elements are those found in the
+ * a list whose elements are those found in the
* sequence. The data type of elements found in the
* sequence is returned in the reference pDataType
*/
@@ -301,8 +301,8 @@
* specified in the "search pattern" must be present in the
* "target pattern". Here "search pattern" is the set of UUIDs
* specified by the service discovery client and "target pattern"
- * is the set of UUIDs present in a service record.
- *
+ * is the set of UUIDs present in a service record.
+ *
* Return 1 if each and every UUID in the search
* pattern exists in the target pattern, 0 if the
* match succeeds and -1 on error.
@@ -420,7 +420,7 @@
sdp_record_t *rec = (sdp_record_t *) list->data;
SDPDBG("Checking svcRec : 0x%x", rec->handle);
-
+
if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
sdp_check_access(rec->handle, &req->device)) {
rsp_count++;
@@ -429,7 +429,7 @@
handleSize += sizeof(uint32_t);
}
}
-
+
SDPDBG("Match count: %d", rsp_count);
buf->data_size += handleSize;
@@ -525,9 +525,8 @@
}
}
-done:
- if (cstate)
- free(cstate);
+done:
+ free(cstate);
if (pattern)
sdp_list_free(pattern, free);
@@ -684,11 +683,11 @@
SDPDBG("SvcRecHandle : 0x%x", handle);
SDPDBG("max_rsp_size : %d", max_rsp_size);
- /*
+ /*
* Calculate Attribute size acording to MTU
* We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
*/
- max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
+ max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
/* pull header for AttributeList byte count */
@@ -745,8 +744,7 @@
buf->buf_size += sizeof(uint16_t);
done:
- if (cstate)
- free(cstate);
+ free(cstate);
if (seq)
sdp_list_free(seq, free);
if (status)
@@ -840,7 +838,7 @@
tmpbuf.buf_size = USHRT_MAX;
memset(tmpbuf.data, 0, USHRT_MAX);
- /*
+ /*
* Calculate Attribute size acording to MTU
* We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
*/
@@ -929,10 +927,8 @@
}
done:
- if (cstate)
- free(cstate);
- if (tmpbuf.data)
- free(tmpbuf.data);
+ free(cstate);
+ free(tmpbuf.data);
if (pattern)
sdp_list_free(pattern, free);
if (seq)
@@ -1040,20 +1036,33 @@
sdp_req_t req;
size = sizeof(sa);
- if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0)
+ if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {
+ error("getpeername: %s", strerror(errno));
return;
+ }
- if (sa.l2_family == AF_BLUETOOTH) {
+ if (sa.l2_family == AF_BLUETOOTH) {
struct l2cap_options lo;
+
memset(&lo, 0, sizeof(lo));
size = sizeof(lo);
- getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size);
+
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) {
+ error("getsockopt: %s", strerror(errno));
+ return;
+ }
+
bacpy(&req.bdaddr, &sa.l2_bdaddr);
req.mtu = lo.omtu;
req.local = 0;
memset(&sa, 0, sizeof(sa));
size = sizeof(sa);
- getsockname(sk, (struct sockaddr *) &sa, &size);
+
+ if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {
+ error("getsockname: %s", strerror(errno));
+ return;
+ }
+
bacpy(&req.device, &sa.l2_bdaddr);
} else {
bacpy(&req.device, BDADDR_ANY);
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index a377ada..1c5f638 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -46,7 +46,7 @@
#include <glib.h>
-#include "logging.h"
+#include "log.h"
#include "sdpd.h"
static GIOChannel *l2cap_io = NULL, *unix_io = NULL;
@@ -114,7 +114,10 @@
}
}
- listen(l2cap_sock, 5);
+ if (listen(l2cap_sock, 5) < 0) {
+ error("listen: %s", strerror(errno));
+ return -1;
+ }
if (!compat) {
unix_sock = -1;
@@ -156,7 +159,6 @@
info("Got Unix socket fd '%d' from environment", unix_sock);
#endif
-
return 0;
}
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 525c12a..cdbb4f4 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -45,13 +45,12 @@
#include <dbus/dbus.h>
#include "sdpd.h"
-#include "logging.h"
+#include "log.h"
#include "manager.h"
+#include "adapter.h"
static sdp_record_t *server = NULL;
-static uint8_t service_classes = 0x00;
-
static uint16_t did_vendor = 0x0000;
static uint16_t did_product = 0x0000;
static uint16_t did_version = 0x0000;
@@ -98,9 +97,9 @@
sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
}
-static void update_svclass_list(const bdaddr_t *src)
+static void update_adapter_svclass_list(struct btd_adapter *adapter)
{
- sdp_list_t *list = sdp_get_record_list();
+ sdp_list_t *list = adapter_get_services(adapter);
uint8_t val = 0;
for (; list; list = list->next) {
@@ -156,19 +155,30 @@
SDPDBG("Service classes 0x%02x", val);
- service_classes = val;
-
- manager_update_svc(src, val);
+ manager_update_svc(adapter, val);
}
-uint8_t get_service_classes(const bdaddr_t *bdaddr)
+static void update_svclass_list(const bdaddr_t *src)
{
- return service_classes;
+ GSList *adapters = manager_get_adapters();
+
+ for (; adapters; adapters = adapters->next) {
+ struct btd_adapter *adapter = adapters->data;
+ bdaddr_t bdaddr;
+
+ adapter_get_address(adapter, &bdaddr);
+
+ if (bacmp(src, BDADDR_ANY) == 0 || bacmp(src, &bdaddr) == 0)
+ update_adapter_svclass_list(adapter);
+ }
+
}
-void create_ext_inquiry_response(const char *name, uint8_t *data)
+void create_ext_inquiry_response(const char *name,
+ int8_t tx_power, sdp_list_t *services,
+ uint8_t *data)
{
- sdp_list_t *list = sdp_get_record_list();
+ sdp_list_t *list = services;
uint8_t *ptr = data;
uint16_t uuid[24];
int i, index = 0;
@@ -189,10 +199,16 @@
ptr += len + 2;
}
+ if (tx_power != 0) {
+ *ptr++ = 2;
+ *ptr++ = 0x0a;
+ *ptr++ = (uint8_t) tx_power;
+ }
+
if (did_vendor != 0x0000) {
uint16_t source = 0x0002;
*ptr++ = 9;
- *ptr++ = 11;
+ *ptr++ = 0x10;
*ptr++ = (source & 0x00ff);
*ptr++ = (source & 0xff00) >> 8;
*ptr++ = (did_vendor & 0x00ff);
@@ -214,6 +230,9 @@
if (rec->svclass.value.uuid16 < 0x1100)
continue;
+ if (rec->svclass.value.uuid16 == PNP_INFO_SVCLASS_ID)
+ continue;
+
if (index > 23) {
ptr[1] = 0x02;
break;
@@ -396,7 +415,7 @@
return -1;
}
- debug("Adding record with handle 0x%05x", rec->handle);
+ DBG("Adding record with handle 0x%05x", rec->handle);
sdp_record_add(src, rec);
@@ -416,7 +435,7 @@
continue;
sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid));
- debug("Record pattern UUID %s", uuid);
+ DBG("Record pattern UUID %s", uuid);
}
update_db_timestamp();
@@ -429,7 +448,7 @@
{
sdp_record_t *rec;
- debug("Removing record with handle 0x%05x", handle);
+ DBG("Removing record with handle 0x%05x", handle);
rec = sdp_record_find(handle);
if (!rec)
@@ -602,7 +621,7 @@
}
update_db_timestamp();
- update_svclass_list(BDADDR_ANY);
+ update_svclass_list(&req->device);
/* Build a rsp buffer */
bt_put_unaligned(htonl(rec->handle), (uint32_t *) rsp->data);
diff --git a/src/sdpd.h b/src/sdpd.h
index 6dadc6b..4abaa55 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
@@ -70,6 +70,7 @@
void sdp_cstate_cache_init(void);
void sdp_cstate_clean_buf(void);
+int record_sort(const void *r1, const void *r2);
void sdp_svcdb_reset(void);
void sdp_svcdb_collect_all(int sock);
void sdp_svcdb_set_collectable(sdp_record_t *rec, int sock);
@@ -93,6 +94,7 @@
int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);
int remove_record_from_server(uint32_t handle);
-uint8_t get_service_classes(const bdaddr_t *bdaddr);
-void create_ext_inquiry_response(const char *name, uint8_t *data);
+void create_ext_inquiry_response(const char *name,
+ int8_t tx_power, sdp_list_t *services,
+ uint8_t *data);
static inline int android_get_control_socket(const char *name);
diff --git a/src/security.c b/src/security.c
index 646921b..ca394e1 100644
--- a/src/security.c
+++ b/src/security.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -47,10 +47,11 @@
#include <dbus/dbus.h>
#include "hcid.h"
-#include "logging.h"
+#include "log.h"
#include "textfile.h"
#include "adapter.h"
+#include "device.h"
#include "dbus-hci.h"
#include "storage.h"
#include "manager.h"
@@ -126,7 +127,8 @@
do {
struct hci_req_data *data;
- GSList *l = g_slist_find_custom(hci_req_queue, &dev_id, hci_req_find_by_devid);
+ GSList *l = g_slist_find_custom(hci_req_queue, &dev_id,
+ hci_req_find_by_devid);
if (!l)
break;
@@ -134,7 +136,8 @@
data = l->data;
data->status = REQ_SENT;
- ret_val = hci_send_cmd(dd, data->ogf, data->ocf, data->clen, data->cparam);
+ ret_val = hci_send_cmd(dd, data->ogf, data->ocf,
+ data->clen, data->cparam);
if (ret_val < 0) {
hci_req_queue = g_slist_remove(hci_req_queue, data);
g_free(data->cparam);
@@ -151,10 +154,10 @@
GSList *l;
struct hci_req_data *match;
-
hci_req_queue = g_slist_append(hci_req_queue, data);
- l = g_slist_find_custom(hci_req_queue, &data->dev_id, hci_req_find_by_devid);
+ l = g_slist_find_custom(hci_req_queue, &data->dev_id,
+ hci_req_find_by_devid);
match = l->data;
if (match->status == REQ_SENT)
@@ -299,12 +302,17 @@
static void link_key_request(int dev, bdaddr_t *sba, bdaddr_t *dba)
{
+ struct btd_adapter *adapter;
+ struct btd_device *device;
struct hci_auth_info_req req;
unsigned char key[16];
char sa[18], da[18];
uint8_t type;
int err;
+ if (!get_adapter_and_device(sba, dba, &adapter, &device, FALSE))
+ device = NULL;
+
ba2str(sba, sa); ba2str(dba, da);
info("link_key_request (sba=%s, dba=%s)", sa, da);
@@ -314,33 +322,37 @@
err = ioctl(dev, HCIGETAUTHINFO, (unsigned long) &req);
if (err < 0) {
if (errno != EINVAL)
- debug("HCIGETAUTHINFO failed %s (%d)",
+ DBG("HCIGETAUTHINFO failed %s (%d)",
strerror(errno), errno);
req.type = 0x00;
}
- debug("kernel auth requirements = 0x%02x", req.type);
+ DBG("kernel auth requirements = 0x%02x", req.type);
- err = read_link_key(sba, dba, key, &type);
- if (err < 0) {
+ if (main_opts.debug_keys && device && device_get_debug_key(device, key))
+ type = 0x03;
+ else if (read_link_key(sba, dba, key, &type) < 0 || type == 0x03) {
/* Link key not found */
hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, 6, dba);
- } else {
- /* Link key found */
+ return;
+ }
+
+ /* Link key found */
+
+ DBG("link key type = 0x%02x", type);
+
+ /* Don't use unauthenticated combination keys if MITM is
+ * required */
+ if (type == 0x04 && req.type != 0xff && (req.type & 0x01))
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
+ 6, dba);
+ else {
link_key_reply_cp lr;
+
memcpy(lr.link_key, key, 16);
bacpy(&lr.bdaddr, dba);
- debug("stored link key type = 0x%02x", type);
-
- /* Don't use debug link keys (0x03) and also don't use
- * unauthenticated combination keys if MITM is required */
- if (type == 0x03 || (type == 0x04 && req.type != 0xff &&
- (req.type & 0x01)))
- hci_send_cmd(dev, OGF_LINK_CTL,
- OCF_LINK_KEY_NEG_REPLY, 6, dba);
- else
- hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_REPLY,
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_REPLY,
LINK_KEY_REPLY_CP_SIZE, &lr);
}
}
@@ -365,11 +377,14 @@
dev_id = hci_devid(sa);
if (dev_id < 0)
err = -errno;
- else
+ else {
err = hcid_dbus_link_key_notify(sba, dba, evt->link_key,
evt->key_type,
io_data[dev_id].pin_length,
old_key_type);
+ io_data[dev_id].pin_length = -1;
+ }
+
if (err < 0) {
uint16_t handle;
@@ -391,8 +406,6 @@
DISCONNECT_CP_SIZE, &cp);
}
}
-
- io_data[dev_id].pin_length = -1;
}
static void return_link_keys(int dev, bdaddr_t *sba, void *ptr)
@@ -413,6 +426,8 @@
info("return_link_keys (sba=%s, dba=%s)", sa, da);
+ hcid_dbus_returned_link_key(sba, &dba);
+
ptr += 22;
}
}
@@ -651,6 +666,18 @@
adapter_set_state(adapter, state);
}
+static inline void remote_features_notify(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_remote_host_features_notify *evt = ptr;
+
+ if (evt->features[0] & 0x01)
+ hcid_dbus_set_legacy_pairing(sba, &evt->bdaddr, FALSE);
+ else
+ hcid_dbus_set_legacy_pairing(sba, &evt->bdaddr, TRUE);
+
+ write_features_info(sba, &evt->bdaddr, NULL, evt->features);
+}
+
static inline void cmd_status(int dev, bdaddr_t *sba, void *ptr)
{
evt_cmd_status *evt = ptr;
@@ -683,7 +710,7 @@
hcid_dbus_setscan_enable_complete(sba);
break;
case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
- hcid_dbus_write_class_complete(sba);
+ adapter_set_class_complete(sba, status);
break;
case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SIMPLE_PAIRING_MODE):
hcid_dbus_write_simple_pairing_mode_complete(sba);
@@ -692,6 +719,10 @@
ptr += sizeof(evt_cmd_complete);
adapter_update_local_name(sba, status, ptr);
break;
+ case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL):
+ ptr += sizeof(evt_cmd_complete);
+ adapter_update_tx_power(sba, status, ptr);
+ break;
};
}
@@ -751,7 +782,8 @@
}
}
-static inline void inquiry_result_with_rssi(int dev, bdaddr_t *sba, int plen, void *ptr)
+static inline void inquiry_result_with_rssi(int dev, bdaddr_t *sba,
+ int plen, void *ptr)
{
uint8_t num = *(uint8_t *) ptr++;
int i;
@@ -790,7 +822,8 @@
}
}
-static inline void extended_inquiry_result(int dev, bdaddr_t *sba, int plen, void *ptr)
+static inline void extended_inquiry_result(int dev, bdaddr_t *sba,
+ int plen, void *ptr)
{
uint8_t num = *(uint8_t *) ptr++;
int i;
@@ -810,7 +843,8 @@
}
}
-static inline void remote_features_information(int dev, bdaddr_t *sba, void *ptr)
+static inline void remote_features_information(int dev, bdaddr_t *sba,
+ void *ptr)
{
evt_read_remote_features_complete *evt = ptr;
bdaddr_t dba;
@@ -821,7 +855,7 @@
if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0)
return;
- write_features_info(sba, &dba, evt->features);
+ write_features_info(sba, &dba, evt->features, NULL);
}
static inline void conn_complete(int dev, int dev_id, bdaddr_t *sba, void *ptr)
@@ -849,7 +883,8 @@
cp_name.pscan_rep_mode = 0x02;
data = hci_req_data_new(dev_id, &evt->bdaddr, OGF_LINK_CTL,
- OCF_REMOTE_NAME_REQ, EVT_REMOTE_NAME_REQ_COMPLETE,
+ OCF_REMOTE_NAME_REQ,
+ EVT_REMOTE_NAME_REQ_COMPLETE,
&cp_name, REMOTE_NAME_REQ_CP_SIZE);
hci_req_queue_append(data);
@@ -858,7 +893,8 @@
ba2str(sba, local_addr);
ba2str(&evt->bdaddr, peer_addr);
- create_name(filename, sizeof(filename), STORAGEDIR, local_addr, "manufacturers");
+ create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
+ "manufacturers");
str = textfile_get(filename, peer_addr);
if (!str) {
@@ -868,7 +904,8 @@
cp.handle = evt->handle;
data = hci_req_data_new(dev_id, &evt->bdaddr, OGF_LINK_CTL,
- OCF_READ_REMOTE_VERSION, EVT_READ_REMOTE_VERSION_COMPLETE,
+ OCF_READ_REMOTE_VERSION,
+ EVT_READ_REMOTE_VERSION_COMPLETE,
&cp, READ_REMOTE_VERSION_CP_SIZE);
hci_req_queue_append(data);
@@ -927,7 +964,8 @@
error("IO channel not found in the io_data table");
}
-static gboolean io_security_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
{
unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
struct hci_dev_info *di = data;
@@ -985,6 +1023,10 @@
remote_features_information(dev, &di->bdaddr, ptr);
break;
+ case EVT_REMOTE_HOST_FEATURES_NOTIFY:
+ remote_features_notify(dev, &di->bdaddr, ptr);
+ break;
+
case EVT_INQUIRY_COMPLETE:
evt = (evt_cmd_status *) ptr;
inquiry_complete(&di->bdaddr, evt->status, FALSE);
@@ -1137,7 +1179,7 @@
chan = g_io_channel_unix_new(dev);
g_io_channel_set_close_on_unref(chan, TRUE);
- io_data[hdev].watch_id = g_io_add_watch_full(chan, G_PRIORITY_HIGH,
+ io_data[hdev].watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW,
G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
io_security_event, di, (GDestroyNotify) g_free);
io_data[hdev].channel = chan;
diff --git a/src/storage.c b/src/storage.c
index e2d7632..e09e257 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
@@ -73,7 +73,7 @@
free(tmp);
- return err;
+ return err < 0 ? -EIO : 0;
}
int write_device_alias(const char *src, const char *dst, const char *alias)
@@ -203,7 +203,7 @@
return 0;
}
-int write_local_name(bdaddr_t *bdaddr, char *name)
+int write_local_name(bdaddr_t *bdaddr, const char *name)
{
char filename[PATH_MAX + 1], str[249];
int i;
@@ -483,21 +483,81 @@
return textfile_put(filename, addr, str);
}
-int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *features)
+int write_features_info(bdaddr_t *local, bdaddr_t *peer,
+ unsigned char *page1, unsigned char *page2)
{
- char filename[PATH_MAX + 1], addr[18], str[17];
+ char filename[PATH_MAX + 1], addr[18];
+ char str[] = "0000000000000000 0000000000000000";
+ char *old_value;
int i;
- memset(str, 0, sizeof(str));
- for (i = 0; i < 8; i++)
- sprintf(str + (i * 2), "%2.2X", features[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);
+
+ 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);
+
+ free(old_value);
+
+ return textfile_put(filename, addr, str);
+}
+
+static int decode_bytes(const char *str, unsigned char *bytes, size_t len)
+{
+ unsigned int i;
+
+ 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");
- create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
ba2str(peer, addr);
- return textfile_put(filename, addr, str);
+
+ 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)
@@ -570,6 +630,11 @@
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);
@@ -698,8 +763,7 @@
/* If the old setting is the same as the requested one, we're done */
if (trusted == trust) {
g_slist_free(services);
- if (str)
- free(str);
+ free(str);
return 0;
}
@@ -719,8 +783,7 @@
g_slist_free(services);
- if (str)
- free(str);
+ free(str);
return ret;
}
@@ -908,10 +971,9 @@
rec_list->recs = sdp_list_append(rec_list->recs, rec);
}
-void delete_all_records(bdaddr_t *src, bdaddr_t *dst)
+void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst)
{
sdp_list_t *records, *seq;
- sdp_record_t *rec;
char srcaddr[18], dstaddr[18];
ba2str(src, srcaddr);
@@ -920,7 +982,7 @@
records = read_records(src, dst);
for (seq = records; seq; seq = seq->next) {
- rec = seq->data;
+ sdp_record_t *rec = seq->data;
delete_record(srcaddr, dstaddr, rec->handle);
}
@@ -928,7 +990,7 @@
sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
}
-sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst)
+sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst)
{
char filename[PATH_MAX + 1];
struct record_list rec_list;
@@ -1141,3 +1203,37 @@
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, "");
+}
diff --git a/src/storage.h b/src/storage.h
index de0e837..eee71d3 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
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, char *name);
+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);
@@ -47,7 +47,8 @@
uint16_t *mtu_result, uint16_t *mtu,
uint16_t *mask_result, uint32_t *mask);
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 *features);
+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);
@@ -63,8 +64,8 @@
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(bdaddr_t *src, bdaddr_t *dst);
-sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst);
+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);
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,
@@ -74,6 +75,9 @@
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);
#define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb"
diff --git a/common/textfile.c b/src/textfile.c
similarity index 98%
rename from common/textfile.c
rename to src/textfile.c
index a755ab7..b1722c8 100644
--- a/common/textfile.c
+++ b/src/textfile.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/common/textfile.h b/src/textfile.h
similarity index 95%
rename from common/textfile.h
rename to src/textfile.h
index a49e249..8353bc7 100644
--- a/common/textfile.h
+++ b/src/textfile.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/common/uinput.h b/src/uinput.h
similarity index 99%
rename from common/uinput.h
rename to src/uinput.h
index 230dfb7..e83986b 100644
--- a/common/uinput.h
+++ b/src/uinput.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/Android.mk b/test/Android.mk
index 68006aa..946dc12 100755
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -9,17 +9,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
hstest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -34,17 +34,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
l2test.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -59,17 +59,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
rctest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -85,17 +85,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
scotest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -110,14 +110,14 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
agent.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
$(call include-path-for, dbus)
LOCAL_SHARED_LIBRARIES := \
@@ -136,17 +136,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
attest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -161,17 +161,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
avtest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -186,20 +186,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
bdaddr.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -215,23 +212,22 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
btiotest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
$(call include-path-for, glib) \
$(call include-path-for, glib)\glib
LOCAL_SHARED_LIBRARIES := \
- libbluetooth \
+ libbluetoothd libbluetooth
LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static \
libglib_static \
@@ -251,18 +247,19 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
hciemu.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
$(call include-path-for, glib) \
$(call include-path-for, glib)\glib
LOCAL_SHARED_LIBRARIES := \
+ libbluetoothd \
libbluetooth \
libc \
libcutils
@@ -284,17 +281,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
lmptest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -309,17 +306,17 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_SRC_FILES:= \
sdptest.c
LOCAL_C_INCLUDES:= \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
diff --git a/test/Makefile.am b/test/Makefile.am
deleted file mode 100644
index 2e58d24..0000000
--- a/test/Makefile.am
+++ /dev/null
@@ -1,55 +0,0 @@
-
-if TEST
-sbin_PROGRAMS = hciemu
-
-bin_PROGRAMS = l2test rctest
-
-noinst_PROGRAMS = sdptest scotest attest hstest avtest lmptest \
- bdaddr agent btiotest
-
-hciemu_LDADD = $(top_builddir)/common/libhelper.a \
- @GLIB_LIBS@ @BLUEZ_LIBS@
-
-l2test_LDADD = @BLUEZ_LIBS@
-
-rctest_LDADD = @BLUEZ_LIBS@
-
-sdptest_LDADD = @BLUEZ_LIBS@
-
-scotest_LDADD = @BLUEZ_LIBS@
-
-attest_LDADD = @BLUEZ_LIBS@
-
-hstest_LDADD = @BLUEZ_LIBS@
-
-avtest_LDADD = @BLUEZ_LIBS@
-
-bdaddr_SOURCES = bdaddr.c
-
-bdaddr_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-lmptest_LDADD = @BLUEZ_LIBS@
-
-agent_LDADD = @DBUS_LIBS@
-
-btiotest_LDADD = $(top_builddir)/common/libhelper.a @GLIB_LIBS@ @BLUEZ_LIBS@
-
-noinst_MANS = bdaddr.8
-
-if MANPAGES
-man_MANS = rctest.1 hciemu.1
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
-endif
-
-INCLUDES = -I$(top_srcdir)/common
-
-EXTRA_DIST = apitest hsplay hsmicro bdaddr.8 rctest.1 hciemu.1 dbusdef.py \
- monitor-bluetooth list-devices test-discovery test-manager \
- test-adapter test-device test-service test-serial \
- test-telephony test-network simple-agent simple-service \
- service-record.dtd service-did.xml service-spp.xml \
- service-opp.xml service-ftp.xml
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/test/agent.c b/test/agent.c
index 4c12ea3..a40039e 100644
--- a/test/agent.c
+++ b/test/agent.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -35,8 +35,8 @@
#include <dbus/dbus.h>
-static char *passkey = NULL;
-
+static char *passkey_value = NULL;
+static int passkey_delay = 0;
static int do_reject = 0;
static volatile sig_atomic_t __io_canceled = 0;
@@ -61,8 +61,7 @@
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID)) {
- fprintf(stderr,
- "Invalid arguments for NameOwnerChanged signal");
+ fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@@ -80,19 +79,17 @@
DBusMessage *reply;
const char *path;
- if (!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)) {
+ 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", "");
+ reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
goto send;
}
@@ -104,8 +101,13 @@
printf("Pincode request for device %s\n", path);
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey,
- DBUS_TYPE_INVALID);
+ 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);
@@ -122,22 +124,19 @@
{
DBusMessage *reply;
const char *path;
- unsigned int int_passkey;
+ unsigned int passkey;
- if (!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)) {
+ 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", "");
+ reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
goto send;
}
@@ -149,10 +148,93 @@
printf("Passkey request for device %s\n", path);
- int_passkey = strtoul(passkey, NULL, 10);
+ if (passkey_delay) {
+ printf("Waiting for %d seconds\n", passkey_delay);
+ sleep(passkey_delay);
+ }
- dbus_message_append_args(reply, DBUS_TYPE_UINT32, &int_passkey,
- DBUS_TYPE_INVALID);
+ 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);
@@ -221,43 +303,6 @@
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 agent_message(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -269,15 +314,19 @@
"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);
- if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize"))
- return authorize_message(conn, msg, data);
-
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@@ -292,12 +341,6 @@
DBusMessage *msg, *reply;
DBusError err;
- if (!dbus_connection_register_object_path(conn, agent_path,
- &agent_table, NULL)) {
- fprintf(stderr, "Can't register object path for agent\n");
- return -1;
- }
-
msg = dbus_message_new_method_call("org.bluez", adapter_path,
"org.bluez.Adapter", "RegisterAgent");
if (!msg) {
@@ -529,6 +572,7 @@
{ "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 }
@@ -546,7 +590,7 @@
snprintf(default_path, sizeof(default_path),
"/org/bluez/agent_%d", getpid());
- while ((opt = getopt_long(argc, argv, "+a:p:c:rh", main_options, NULL)) != EOF) {
+ while ((opt = getopt_long(argc, argv, "+a:p:c:d:rh", main_options, NULL)) != EOF) {
switch(opt) {
case 'a':
adapter_id = optarg;
@@ -561,6 +605,9 @@
case 'c':
capabilities = optarg;
break;
+ case 'd':
+ passkey_delay = atoi(optarg);
+ break;
case 'r':
do_reject = 1;
break;
@@ -581,7 +628,7 @@
exit(1);
}
- passkey = strdup(argv[0]);
+ passkey_value = strdup(argv[0]);
if (argc > 1)
device = strdup(argv[1]);
@@ -599,6 +646,12 @@
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) {
@@ -639,7 +692,7 @@
free(adapter_path);
free(agent_path);
- free(passkey);
+ free(passkey_value);
dbus_connection_unref(conn);
diff --git a/test/attest.c b/test/attest.c
index 8813f41..12ba682 100644
--- a/test/attest.c
+++ b/test/attest.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2001-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2001-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/avtest.c b/test/avtest.c
index 6ec6035..168326f 100644
--- a/test/avtest.c
+++ b/test/avtest.c
@@ -2,7 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2007-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
*
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +26,844 @@
#include <config.h>
#endif
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+
+#define AVDTP_PKT_TYPE_SINGLE 0x00
+#define AVDTP_PKT_TYPE_START 0x01
+#define AVDTP_PKT_TYPE_CONTINUE 0x02
+#define AVDTP_PKT_TYPE_END 0x03
+
+#define AVDTP_MSG_TYPE_COMMAND 0x00
+#define AVDTP_MSG_TYPE_GEN_REJECT 0x01
+#define AVDTP_MSG_TYPE_ACCEPT 0x02
+#define AVDTP_MSG_TYPE_REJECT 0x03
+
+#define AVDTP_DISCOVER 0x01
+#define AVDTP_GET_CAPABILITIES 0x02
+#define AVDTP_SET_CONFIGURATION 0x03
+#define AVDTP_GET_CONFIGURATION 0x04
+#define AVDTP_RECONFIGURE 0x05
+#define AVDTP_OPEN 0x06
+#define AVDTP_START 0x07
+#define AVDTP_CLOSE 0x08
+#define AVDTP_SUSPEND 0x09
+#define AVDTP_ABORT 0x0A
+
+#define AVDTP_SEP_TYPE_SOURCE 0x00
+#define AVDTP_SEP_TYPE_SINK 0x01
+
+#define AVDTP_MEDIA_TYPE_AUDIO 0x00
+#define AVDTP_MEDIA_TYPE_VIDEO 0x01
+#define AVDTP_MEDIA_TYPE_MULTIMEDIA 0x02
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avdtp_header {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+ uint8_t signal_id:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct seid_info {
+ uint8_t rfa0:1;
+ uint8_t inuse:1;
+ uint8_t seid:6;
+ uint8_t rfa2:3;
+ uint8_t type:1;
+ uint8_t media_type:4;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+ uint8_t no_of_packets;
+ uint8_t signal_id:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+} __attribute__ ((packed));
+
+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
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+ uint8_t rfa0:2;
+ uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct seid_info {
+ uint8_t seid:6;
+ uint8_t inuse:1;
+ uint8_t rfa0:1;
+ uint8_t media_type:4;
+ uint8_t type:1;
+ uint8_t rfa2:3;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+ uint8_t no_of_packets;
+ uint8_t rfa0:2;
+ uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+} __attribute__ ((packed));
+
+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
+
+#else
+#error "Unknown byte order"
+#endif
+
+#define AVCTP_COMMAND 0
+#define AVCTP_RESPONSE 1
+
+#define AVCTP_PACKET_SINGLE 0
+
+static const unsigned char media_transport[] = {
+ 0x01, /* Media transport category */
+ 0x00,
+ 0x07, /* Media codec category */
+ 0x06,
+ 0x00, /* Media type audio */
+ 0x00, /* Codec SBC */
+ 0x22, /* 44.1 kHz, stereo */
+ 0x15, /* 16 blocks, 8 subbands */
+ 0x02,
+ 0x33,
+};
+
+static int media_sock = -1;
+
+static void dump_avctp_header(struct avctp_header *hdr)
+{
+ printf("TL %d PT %d CR %d IPID %d PID 0x%04x\n", hdr->transaction,
+ hdr->packet_type, hdr->cr, hdr->ipid, ntohs(hdr->pid));
+}
+
+static void dump_avdtp_header(struct avdtp_header *hdr)
+{
+ printf("TL %d PT %d MT %d SI %d\n", hdr->transaction,
+ hdr->packet_type, hdr->message_type, hdr->signal_id);
+}
+
+static void dump_buffer(const unsigned char *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ printf("%02x ", buf[i]);
+ printf("\n");
+}
+
+static void process_avdtp(int srv_sk, int sk, unsigned char reject,
+ int fragment)
+{
+ unsigned char buf[672];
+ ssize_t len;
+
+ while (1) {
+ struct avdtp_header *hdr = (void *) buf;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len <= 0) {
+ perror("Read failed");
+ break;
+ }
+
+ dump_buffer(buf, len);
+ dump_avdtp_header(hdr);
+
+ if (hdr->packet_type != AVDTP_PKT_TYPE_SINGLE) {
+ fprintf(stderr, "Only single packets are supported\n");
+ break;
+ }
+
+ if (hdr->message_type != AVDTP_MSG_TYPE_COMMAND) {
+ fprintf(stderr, "Ignoring non-command messages\n");
+ continue;
+ }
+
+ switch (hdr->signal_id) {
+ case AVDTP_DISCOVER:
+ if (reject == AVDTP_DISCOVER) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[2] = 0x29; /* Unsupported configuration */
+ printf("Rejecting discover command\n");
+ len = write(sk, buf, 3);
+ } else {
+ struct seid_info *sei = (void *) (buf + 2);
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+ sei->seid = 0x01;
+ sei->type = AVDTP_SEP_TYPE_SINK;
+ sei->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ printf("Accepting discover command\n");
+ len = write(sk, buf, 4);
+ }
+ break;
+
+ case AVDTP_GET_CAPABILITIES:
+ if (reject == AVDTP_GET_CAPABILITIES) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[2] = 0x29; /* Unsupported configuration */
+ printf("Rejecting get capabilties command\n");
+ len = write(sk, buf, 3);
+ } else if (fragment) {
+ struct avdtp_start_header *start = (void *) buf;
+
+ printf("Sending fragmented reply to getcap\n");
+
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+
+ /* Start packet */
+ hdr->packet_type = AVDTP_PKT_TYPE_START;
+ start->signal_id = AVDTP_GET_CAPABILITIES;
+ start->no_of_packets = 3;
+ memcpy(&buf[3], media_transport,
+ sizeof(media_transport));
+ len = write(sk, buf,
+ 3 + sizeof(media_transport));
+
+ /* Continue packet */
+ hdr->packet_type = AVDTP_PKT_TYPE_CONTINUE;
+ memcpy(&buf[1], media_transport,
+ sizeof(media_transport));
+ len = write(sk, buf,
+ 1 + sizeof(media_transport));
+
+ /* End packet */
+ hdr->packet_type = AVDTP_PKT_TYPE_END;
+ memcpy(&buf[1], media_transport,
+ sizeof(media_transport));
+ len = write(sk, buf,
+ 1 + sizeof(media_transport));
+ } else {
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ memcpy(&buf[2], media_transport,
+ sizeof(media_transport));
+ printf("Accepting get capabilities command\n");
+ len = write(sk, buf,
+ 2 + sizeof(media_transport));
+ }
+ break;
+
+ case AVDTP_SET_CONFIGURATION:
+ if (reject == AVDTP_SET_CONFIGURATION) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[2] = buf[4];
+ buf[3] = 0x13; /* SEP In Use */
+ printf("Rejecting set configuration command\n");
+ len = write(sk, buf, 4);
+ } else {
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ printf("Accepting set configuration command\n");
+ len = write(sk, buf, 2);
+ }
+ break;
+
+ case AVDTP_GET_CONFIGURATION:
+ if (reject == AVDTP_GET_CONFIGURATION) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[2] = 0x12; /* Bad ACP SEID */
+ printf("Rejecting get configuration command\n");
+ len = write(sk, buf, 3);
+ } else {
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ printf("Accepting get configuration command\n");
+ len = write(sk, buf, 2);
+ }
+ break;
+
+ case AVDTP_OPEN:
+ if (reject == AVDTP_OPEN) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[2] = 0x31; /* Bad State */
+ printf("Rejecting open command\n");
+ len = write(sk, buf, 3);
+ } else {
+ struct sockaddr_l2 addr;
+ socklen_t optlen;
+
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ printf("Accepting open command\n");
+ len = write(sk, buf, 2);
+
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ media_sock = accept(srv_sk,
+ (struct sockaddr *) &addr,
+ &optlen);
+ if (media_sock < 0) {
+ perror("Accept failed");
+ break;
+ }
+ }
+ break;
+
+ case AVDTP_START:
+ if (reject == AVDTP_ABORT)
+ printf("Ignoring start to cause abort");
+ else if (reject == AVDTP_START) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[3] = 0x31; /* Bad State */
+ printf("Rejecting start command\n");
+ len = write(sk, buf, 4);
+ } else {
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ printf("Accepting start command\n");
+ len = write(sk, buf, 2);
+ }
+ break;
+
+ case AVDTP_CLOSE:
+ if (reject == AVDTP_CLOSE) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[2] = 0x31; /* Bad State */
+ printf("Rejecting close command\n");
+ len = write(sk, buf, 3);
+ } else {
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ printf("Accepting close command\n");
+ len = write(sk, buf, 2);
+ if (media_sock >= 0) {
+ close(media_sock);
+ media_sock = -1;
+ }
+ }
+ break;
+
+ case AVDTP_SUSPEND:
+ if (reject == AVDTP_SUSPEND) {
+ hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+ buf[3] = 0x31; /* Bad State */
+ printf("Rejecting suspend command\n");
+ len = write(sk, buf, 4);
+ } else {
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ printf("Accepting suspend command\n");
+ len = write(sk, buf, 2);
+ }
+ break;
+
+ case AVDTP_ABORT:
+ hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+ printf("Accepting abort command\n");
+ len = write(sk, buf, 2);
+ if (media_sock >= 0) {
+ close(media_sock);
+ media_sock = -1;
+ }
+ break;
+
+ default:
+ buf[1] = 0x00;
+ printf("Unknown command\n");
+ len = write(sk, buf, 2);
+ break;
+ }
+ }
+}
+
+static void process_avctp(int sk, int reject)
+{
+ unsigned char buf[672];
+ ssize_t len;
+
+ while (1) {
+ struct avctp_header *hdr = (void *) buf;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len <= 0) {
+ perror("Read failed");
+ break;
+ }
+
+ dump_buffer(buf, len);
+
+ if (len >= AVCTP_HEADER_LENGTH)
+ dump_avctp_header(hdr);
+ }
+}
+
+static int set_minimum_mtu(int sk)
+{
+ struct l2cap_options l2o;
+ socklen_t optlen;
+
+ memset(&l2o, 0, sizeof(l2o));
+ optlen = sizeof(l2o);
+
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &optlen) < 0) {
+ perror("getsockopt");
+ return -1;
+ }
+
+ l2o.imtu = 48;
+ l2o.omtu = 48;
+
+ if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) {
+ perror("setsockopt");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void do_listen(const bdaddr_t *src, unsigned char reject, int fragment)
+{
+ struct sockaddr_l2 addr;
+ socklen_t optlen;
+ int sk, nsk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0) {
+ perror("Can't create socket");
+ return;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+ addr.l2_psm = htobs(25);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Can't bind socket");
+ goto error;
+ }
+
+ if (fragment)
+ set_minimum_mtu(sk);
+
+ if (listen(sk, 10)) {
+ perror("Can't listen on the socket");
+ goto error;
+ }
+
+ while (1) {
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
+ if (nsk < 0) {
+ perror("Accept failed");
+ continue;
+ }
+
+ process_avdtp(sk, nsk, reject, fragment);
+
+ if (media_sock >= 0) {
+ close(media_sock);
+ media_sock = -1;
+ }
+
+ close(nsk);
+ }
+
+error:
+ close(sk);
+}
+
+static int do_connect(const bdaddr_t *src, const bdaddr_t *dst, int avctp,
+ int fragment)
+{
+ struct sockaddr_l2 addr;
+ int sk, err;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0) {
+ perror("Can't create socket");
+ 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) {
+ perror("Can't bind socket");
+ goto error;
+ }
+
+ if (fragment)
+ set_minimum_mtu(sk);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(avctp ? 23 : 25);
+
+ err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0) {
+ perror("Unable to connect");
+ goto error;
+ }
+
+ return sk;
+
+error:
+ close(sk);
+ return -1;
+}
+
+static void do_avdtp_send(int sk, const bdaddr_t *src, const bdaddr_t *dst,
+ unsigned char cmd, int invalid, int preconf)
+{
+ unsigned char buf[672];
+ struct avdtp_header *hdr = (void *) buf;
+ ssize_t len;
+
+ memset(buf, 0, sizeof(buf));
+
+ switch (cmd) {
+ case AVDTP_DISCOVER:
+ if (invalid)
+ hdr->message_type = 0x01;
+ else
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_DISCOVER;
+ len = write(sk, buf, 2);
+ break;
+
+ case AVDTP_GET_CAPABILITIES:
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_GET_CAPABILITIES;
+ buf[2] = 1 << 2; /* SEID 1 */
+ len = write(sk, buf, invalid ? 2 : 3);
+ break;
+
+ case AVDTP_SET_CONFIGURATION:
+ if (preconf)
+ do_avdtp_send(sk, src, dst, cmd, 0, 0);
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_SET_CONFIGURATION;
+ buf[2] = 1 << 2; /* ACP SEID */
+ buf[3] = 1 << 2; /* INT SEID */
+ memcpy(&buf[4], media_transport, sizeof(media_transport));
+ if (invalid)
+ buf[5] = 0x01; /* LOSC != 0 */
+ len = write(sk, buf, 4 + sizeof(media_transport));
+ break;
+
+ case AVDTP_GET_CONFIGURATION:
+ if (preconf)
+ do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_GET_CONFIGURATION;
+ if (invalid)
+ buf[2] = 13 << 2; /* Invalid ACP SEID */
+ else
+ buf[2] = 1 << 2; /* Valid ACP SEID */
+ len = write(sk, buf, 3);
+ break;
+
+ case AVDTP_OPEN:
+ if (preconf)
+ do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_OPEN;
+ buf[2] = 1 << 2; /* ACP SEID */
+ len = write(sk, buf, 3);
+ break;
+
+ case AVDTP_START:
+ if (preconf)
+ do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+ if (!invalid)
+ do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, 0);
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_START;
+ buf[2] = 1 << 2; /* ACP SEID */
+ len = write(sk, buf, 3);
+ break;
+
+ case AVDTP_CLOSE:
+ if (preconf) {
+ do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+ do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, 0);
+ }
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_CLOSE;
+ if (invalid)
+ buf[2] = 13 << 2; /* Invalid ACP SEID */
+ else
+ buf[2] = 1 << 2; /* Valid ACP SEID */
+ len = write(sk, buf, 3);
+ break;
+
+ case AVDTP_SUSPEND:
+ if (invalid)
+ do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, preconf);
+ else
+ do_avdtp_send(sk, src, dst, AVDTP_START, 0, preconf);
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_SUSPEND;
+ buf[2] = 1 << 2; /* ACP SEID */
+ len = write(sk, buf, 3);
+ break;
+
+ case AVDTP_ABORT:
+ do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, 1);
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = AVDTP_ABORT;
+ buf[2] = 1 << 2; /* ACP SEID */
+ len = write(sk, buf, 3);
+ break;
+
+ default:
+ hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+ hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ hdr->signal_id = cmd;
+ len = write(sk, buf, 2);
+ break;
+ }
+
+ do {
+ len = read(sk, buf, sizeof(buf));
+
+ dump_buffer(buf, len);
+ dump_avdtp_header(hdr);
+ } while (len < 2 || (hdr->message_type != AVDTP_MSG_TYPE_ACCEPT &&
+ hdr->message_type != AVDTP_MSG_TYPE_REJECT &&
+ hdr->message_type != AVDTP_MSG_TYPE_GEN_REJECT));
+
+ if (cmd == AVDTP_OPEN && len >= 2 &&
+ hdr->message_type == AVDTP_MSG_TYPE_ACCEPT)
+ media_sock = do_connect(src, dst, 0, 0);
+}
+
+static void do_avctp_send(int sk, int invalid)
+{
+ unsigned char buf[672];
+ struct avctp_header *hdr = (void *) buf;
+ unsigned char play_pressed[] = { 0x00, 0x48, 0x7c, 0x44, 0x00 };
+ ssize_t len;
+
+ memset(buf, 0, sizeof(buf));
+
+ hdr->packet_type = AVCTP_PACKET_SINGLE;
+ hdr->cr = AVCTP_COMMAND;
+ if (invalid)
+ hdr->pid = 0xffff;
+ else
+ hdr->pid = htons(AV_REMOTE_SVCLASS_ID);
+
+ memcpy(&buf[AVCTP_HEADER_LENGTH], play_pressed, sizeof(play_pressed));
+
+ len = write(sk, buf, AVCTP_HEADER_LENGTH + sizeof(play_pressed));
+
+ len = read(sk, buf, sizeof(buf));
+
+ dump_buffer(buf, len);
+ if (len >= AVCTP_HEADER_LENGTH)
+ dump_avctp_header(hdr);
+}
+
+static void usage()
+{
+ printf("avtest - Audio/Video testing ver %s\n", VERSION);
+ printf("Usage:\n"
+ "\tavtest [options] [remote address]\n");
+ printf("Options:\n"
+ "\t--device <hcidev> HCI device\n"
+ "\t--reject <command> Reject command\n"
+ "\t--send <command> Send command\n"
+ "\t--preconf Configure stream before actual command\n"
+ "\t--wait <N> Wait N seconds before exiting\n"
+ "\t--fragment Use minimum MTU and fragmented messages\n"
+ "\t--invalid <command> Send invalid command\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device", 1, 0, 'i' },
+ { "reject", 1, 0, 'r' },
+ { "send", 1, 0, 's' },
+ { "invalid", 1, 0, 'f' },
+ { "preconf", 0, 0, 'c' },
+ { "fragment", 0, 0, 'F' },
+ { "avctp", 0, 0, 'C' },
+ { "wait", 1, 0, 'w' },
+ { 0, 0, 0, 0 }
+};
+
+static unsigned char parse_cmd(const char *arg)
+{
+ if (!strncmp(arg, "discov", 6))
+ return AVDTP_DISCOVER;
+ else if (!strncmp(arg, "capa", 4))
+ return AVDTP_GET_CAPABILITIES;
+ else if (!strncmp(arg, "getcapa", 7))
+ return AVDTP_GET_CAPABILITIES;
+ else if (!strncmp(arg, "setconf", 7))
+ return AVDTP_SET_CONFIGURATION;
+ else if (!strncmp(arg, "getconf", 7))
+ return AVDTP_GET_CONFIGURATION;
+ else if (!strncmp(arg, "open", 4))
+ return AVDTP_OPEN;
+ else if (!strncmp(arg, "start", 5))
+ return AVDTP_START;
+ else if (!strncmp(arg, "close", 5))
+ return AVDTP_CLOSE;
+ else if (!strncmp(arg, "suspend", 7))
+ return AVDTP_SUSPEND;
+ else if (!strncmp(arg, "abort", 7))
+ return AVDTP_ABORT;
+ else
+ return atoi(arg);
+}
+
+enum {
+ MODE_NONE, MODE_REJECT, MODE_SEND,
+};
+
int main(int argc, char *argv[])
{
+ unsigned char cmd = 0x00;
+ bdaddr_t src, dst;
+ int opt, mode = MODE_NONE, sk, invalid = 0, preconf = 0, fragment = 0;
+ int avctp = 0, wait_before_exit = 0;
+
+ bacpy(&src, BDADDR_ANY);
+ bacpy(&dst, BDADDR_ANY);
+
+ while ((opt = getopt_long(argc, argv, "+i:r:s:f:hcFCw:",
+ main_options, NULL)) != EOF) {
+ switch (opt) {
+ case 'i':
+ if (!strncmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &src);
+ else
+ str2ba(optarg, &src);
+ break;
+
+ case 'r':
+ mode = MODE_REJECT;
+ cmd = parse_cmd(optarg);
+ break;
+
+ case 'f':
+ invalid = 1;
+ /* Intentionally missing break */
+
+ case 's':
+ mode = MODE_SEND;
+ cmd = parse_cmd(optarg);
+ break;
+
+ case 'c':
+ preconf = 1;
+ break;
+
+ case 'F':
+ fragment = 1;
+ break;
+
+ case 'C':
+ avctp = 1;
+ break;
+
+ case 'w':
+ wait_before_exit = atoi(optarg);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ if (argv[optind])
+ str2ba(argv[optind], &dst);
+
+ if (avctp) {
+ avctp = mode;
+ mode = MODE_SEND;
+ }
+
+ switch (mode) {
+ case MODE_REJECT:
+ do_listen(&src, cmd, fragment);
+ break;
+ case MODE_SEND:
+ sk = do_connect(&src, &dst, avctp, fragment);
+ if (sk < 0)
+ exit(1);
+ if (avctp) {
+ if (avctp == MODE_SEND)
+ do_avctp_send(sk, invalid);
+ else
+ process_avctp(sk, cmd);
+ } else
+ do_avdtp_send(sk, &src, &dst, cmd, invalid, preconf);
+ if (wait_before_exit) {
+ printf("Waiting %d seconds before exiting\n", wait_before_exit);
+ sleep(wait_before_exit);
+ }
+ if (media_sock >= 0)
+ close(media_sock);
+ close(sk);
+ break;
+ default:
+ fprintf(stderr, "No operating mode specified!\n");
+ exit(1);
+ }
+
return 0;
}
diff --git a/test/bdaddr.c b/test/bdaddr.c
index 77193f4..683b3b9 100644
--- a/test/bdaddr.c
+++ b/test/bdaddr.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/btiotest.c b/test/btiotest.c
index 128df63..c02a25a 100644
--- a/test/btiotest.c
+++ b/test/btiotest.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2009 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009-2010 Nokia Corporation
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/gaptest.c b/test/gaptest.c
new file mode 100644
index 0000000..3e9f534
--- /dev/null
+++ b/test/gaptest.c
@@ -0,0 +1,335 @@
+/*
+ *
+ * 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.c b/test/hciemu.c
index 66bd84f..195e933 100644
--- a/test/hciemu.c
+++ b/test/hciemu.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -296,7 +296,7 @@
he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
he->evt = EVT_CMD_COMPLETE;
- he->plen = EVT_CMD_COMPLETE_SIZE + plen;
+ he->plen = EVT_CMD_COMPLETE_SIZE + plen;
cc = (void *) ptr; ptr += EVT_CMD_COMPLETE_SIZE;
@@ -328,7 +328,7 @@
he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
he->evt = EVT_CONN_REQUEST;
- he->plen = EVT_CONN_REQUEST_SIZE;
+ he->plen = EVT_CONN_REQUEST_SIZE;
cr = (void *) ptr; ptr += EVT_CONN_REQUEST_SIZE;
@@ -356,7 +356,7 @@
he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
he->evt = EVT_CONN_COMPLETE;
- he->plen = EVT_CONN_COMPLETE_SIZE;
+ he->plen = EVT_CONN_COMPLETE_SIZE;
cc = (void *) ptr; ptr += EVT_CONN_COMPLETE_SIZE;
diff --git a/test/hstest.c b/test/hstest.c
index b6a58c6..08f2257 100644
--- a/test/hstest.c
+++ b/test/hstest.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -277,7 +277,7 @@
case PLAY:
rlen = read(fd, buf, rlen);
- wlen = 0;
+ wlen = 0;
p = buf;
while (rlen > sco_mtu) {
wlen += write(sd, p, sco_mtu);
diff --git a/audio/ipctest-a2dp-easy.test b/test/ipctest-a2dp-easy.test
similarity index 100%
rename from audio/ipctest-a2dp-easy.test
rename to test/ipctest-a2dp-easy.test
diff --git a/audio/ipctest-a2dp-resume-fast.test b/test/ipctest-a2dp-resume-fast.test
similarity index 100%
rename from audio/ipctest-a2dp-resume-fast.test
rename to test/ipctest-a2dp-resume-fast.test
diff --git a/audio/ipctest-hsp-a2dp-switch.test b/test/ipctest-hsp-a2dp-switch.test
similarity index 100%
rename from audio/ipctest-hsp-a2dp-switch.test
rename to test/ipctest-hsp-a2dp-switch.test
diff --git a/audio/ipctest-hsp-easy.test b/test/ipctest-hsp-easy.test
similarity index 100%
rename from audio/ipctest-hsp-easy.test
rename to test/ipctest-hsp-easy.test
diff --git a/audio/ipctest-init-shutdown.test b/test/ipctest-init-shutdown.test
similarity index 100%
rename from audio/ipctest-init-shutdown.test
rename to test/ipctest-init-shutdown.test
diff --git a/audio/ipctest.c b/test/ipctest.c
similarity index 98%
rename from audio/ipctest.c
rename to test/ipctest.c
index d18f62e..9fdfac4 100644
--- a/audio/ipctest.c
+++ b/test/ipctest.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2009 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
*
@@ -1029,8 +1029,7 @@
if (sscanf(line, "%*s %as", &address) != 1)
DBG("set with bdaddr BDADDR");
- if (u->address)
- free(u->address);
+ free(u->address);
u->address = address;
DBG("bdaddr %s", u->address);
@@ -1049,8 +1048,7 @@
DBG("set with profile [hsp|a2dp]");
}
- if (profile)
- free(profile);
+ free(profile);
DBG("profile %s", u->transport == BT_CAPABILITIES_TRANSPORT_SCO ?
"hsp" : "a2dp");
}
diff --git a/test/l2test.c b/test/l2test.c
index 6ba50c3..0bb46f3 100644
--- a/test/l2test.c
+++ b/test/l2test.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -60,6 +60,8 @@
LSEND,
SENDDUMP,
LSENDDUMP,
+ LSENDRECV,
+ CSENDRECV,
INFOREQ,
PAIRING,
};
@@ -70,6 +72,15 @@
static int imtu = 672;
static int omtu = 0;
+/* Default FCS option */
+static int fcs = 0x01;
+
+/* Default Transmission Window */
+static int txwin_size = 63;
+
+/* Default Max Transmission */
+static int max_transmit = 3;
+
/* Default data size */
static long data_size = -1;
static long buffer_size = 2048;
@@ -217,8 +228,11 @@
/* Set new options */
opts.omtu = omtu;
opts.imtu = imtu;
- if (rfcmode > 0)
- opts.mode = rfcmode;
+ opts.mode = rfcmode;
+
+ opts.fcs = fcs;
+ opts.txwin_size = txwin_size;
+ opts.max_tx = max_transmit;
if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
@@ -380,6 +394,10 @@
if (rfcmode > 0)
opts.mode = rfcmode;
+ opts.fcs = fcs;
+ opts.txwin_size = txwin_size;
+ opts.max_tx = max_transmit;
+
if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
strerror(errno), errno);
@@ -768,6 +786,22 @@
dump_mode(sk);
}
+static void send_and_recv_mode(int sk)
+{
+ int flags;
+
+ if ((flags = fcntl(sk, F_GETFL, 0)) < 0)
+ flags = 0;
+ fcntl(sk, F_SETFL, flags | O_NONBLOCK);
+
+ /* fork for duplex channel */
+ if (fork())
+ send_mode(sk);
+ else
+ recv_mode(sk);
+ return;
+}
+
static void reconnect_mode(char *svr)
{
while (1) {
@@ -1017,6 +1051,8 @@
"\t-w listen and send\n"
"\t-d listen and dump incoming data\n"
"\t-x listen, then send, then dump incoming data\n"
+ "\t-t listen, then send and receive at the same time\n"
+ "\t-q connect, then send and receive at the same time\n"
"\t-s connect and send\n"
"\t-u connect and receive\n"
"\t-n connect and be silent\n"
@@ -1030,14 +1066,18 @@
"\t[-b bytes] [-i device] [-P psm]\n"
"\t[-I imtu] [-O omtu]\n"
"\t[-L seconds] enable SO_LINGER\n"
- "\t[-F seconds] enable deferred setup\n"
+ "\t[-W seconds] enable deferred setup\n"
"\t[-B filename] use data packets from file\n"
"\t[-N num] send num frames (default = infinite)\n"
"\t[-C num] send num frames before delay (default = 1)\n"
"\t[-D milliseconds] delay after sending num frames (default = 0)\n"
"\t[-X mode] select retransmission/flow-control mode\n"
+ "\t[-F fcs] use CRC16 check (default = 1)\n"
+ "\t[-Q num] Max Transmit value (default = 3)\n"
+ "\t[-Z size] Transmission Window size (default = 63)\n"
"\t[-R] reliable mode\n"
"\t[-G] use connectionless channel (datagram)\n"
+ "\t[-U] use sock stream\n"
"\t[-A] request authentication\n"
"\t[-E] request encryption\n"
"\t[-S] secure connection\n"
@@ -1052,7 +1092,7 @@
bacpy(&bdaddr, BDADDR_ANY);
- while ((opt=getopt(argc,argv,"rdscuwmnxyzpb:i:P:I:O:B:N:L:F:C:D:X:RGAESMT")) != EOF) {
+ while ((opt=getopt(argc,argv,"rdscuwmntqxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:Q:Z:RUGAESMT")) != EOF) {
switch(opt) {
case 'r':
mode = RECV;
@@ -1091,6 +1131,15 @@
need_addr = 1;
break;
+ case 't':
+ mode = LSENDRECV;
+ break;
+
+ case 'q':
+ mode = CSENDRECV;
+ need_addr = 1;
+ break;
+
case 'x':
mode = LSENDDUMP;
break;
@@ -1136,7 +1185,7 @@
linger = atoi(optarg);
break;
- case 'F':
+ case 'W':
defer_setup = atoi(optarg);
break;
@@ -1163,6 +1212,10 @@
rfcmode = atoi(optarg);
break;
+ case 'F':
+ fcs = atoi(optarg);
+ break;
+
case 'R':
reliable = 1;
break;
@@ -1187,10 +1240,22 @@
socktype = SOCK_DGRAM;
break;
+ case 'U':
+ socktype = SOCK_STREAM;
+ break;
+
case 'T':
timestamp = 1;
break;
+ case 'Q':
+ max_transmit = atoi(optarg);
+ break;
+
+ case 'Z':
+ txwin_size = atoi(optarg);
+ break;
+
default:
usage();
exit(1);
@@ -1269,6 +1334,18 @@
do_listen(senddump_mode);
break;
+ case LSENDRECV:
+ do_listen(send_and_recv_mode);
+ break;
+
+ case CSENDRECV:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+
+ send_and_recv_mode(sk);
+ break;
+
case INFOREQ:
info_request(argv[optind]);
exit(0);
diff --git a/test/list-devices b/test/list-devices
index 511d0cf..9120714 100755
--- a/test/list-devices
+++ b/test/list-devices
@@ -40,6 +40,9 @@
if (key == "Devices"):
list = extract_objects(value)
print " %s = %s" % (key, list)
+ elif (key == "UUIDs"):
+ list = extract_uuids(value)
+ print " %s = %s" % (key, list)
else:
print " %s = %s" % (key, value)
diff --git a/test/lmptest.c b/test/lmptest.c
index ce30bb1..549ae12 100644
--- a/test/lmptest.c
+++ b/test/lmptest.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/rctest.1 b/test/rctest.1
index b83d694..dfedbef 100644
--- a/test/rctest.1
+++ b/test/rctest.1
@@ -54,7 +54,7 @@
.BI -L\ seconds
enable SO_LINGER options for \fIseconds\fR
.TP
-.BI -F\ seconds
+.BI -W\ seconds
enable deferred setup for \fIseconds\fR
.TP
.BI -B\ filename
diff --git a/test/rctest.c b/test/rctest.c
index a246262..b3804f5 100644
--- a/test/rctest.c
+++ b/test/rctest.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -436,7 +436,7 @@
if (r < 0)
syslog(LOG_ERR, "Read failed: %s (%d)",
strerror(errno), errno);
- return;
+ return;
}
if (timestamp) {
@@ -459,15 +459,15 @@
seq = sq;
}
seq++;
-
+
/* Check length */
l = btohs(*(uint16_t *) (buf + 4));
if (r != l) {
syslog(LOG_INFO, "size missmatch: %d -> %d", r, l);
continue;
}
-
- /* Verify data */
+
+ /* Verify data */
for (i = 6; i < r; i++) {
if (buf[i] != 0x7f)
syslog(LOG_INFO, "data missmatch: byte %d 0x%2.2x", i, buf[i]);
@@ -511,7 +511,7 @@
*(uint32_t *) buf = htobl(seq);
*(uint16_t *) (buf + 4) = htobs(data_size);
seq++;
-
+
if (send(sk, buf, data_size, 0) <= 0) {
syslog(LOG_ERR, "Send failed: %s (%d)",
strerror(errno), errno);
@@ -581,7 +581,7 @@
printf("Options:\n"
"\t[-b bytes] [-i device] [-P channel] [-U uuid]\n"
"\t[-L seconds] enabled SO_LINGER option\n"
- "\t[-F seconds] enable deferred setup\n"
+ "\t[-W seconds] enable deferred setup\n"
"\t[-B filename] use data packets from file\n"
"\t[-N num] number of frames to send\n"
"\t[-C num] send num frames before delay (default = 1)\n"
@@ -600,7 +600,7 @@
bacpy(&bdaddr, BDADDR_ANY);
- while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:U:B:N:MAESL:F:C:D:T")) != EOF) {
+ while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:U:B:N:MAESL:W:C:D:T")) != EOF) {
switch (opt) {
case 'r':
mode = RECV;
@@ -683,7 +683,7 @@
linger = atoi(optarg);
break;
- case 'F':
+ case 'W':
defer_setup = atoi(optarg);
break;
diff --git a/test/scotest.c b/test/scotest.c
index d72c610..d5aa940 100644
--- a/test/scotest.c
+++ b/test/scotest.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -235,7 +235,7 @@
if (r < 0)
syslog(LOG_ERR, "Read failed: %s (%d)",
strerror(errno), errno);
- return;
+ return;
}
total += r;
}
diff --git a/test/sdptest.c b/test/sdptest.c
index cccb1da..480a468 100644
--- a/test/sdptest.c
+++ b/test/sdptest.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/test/test-adapter b/test/test-adapter
index 4c1a28a..00ef6f5 100755
--- a/test/test-adapter
+++ b/test/test-adapter
@@ -3,15 +3,29 @@
import sys
import dbus
import time
+from optparse import OptionParser, make_option
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
"org.bluez.Adapter")
-if (len(sys.argv) < 2):
+if (len(args) < 1):
print "Usage: %s <command>" % (sys.argv[0])
print ""
print " address"
@@ -24,80 +38,80 @@
print " discovering"
sys.exit(1)
-if (sys.argv[1] == "address"):
+if (args[0] == "address"):
properties = adapter.GetProperties()
print properties["Address"]
sys.exit(0)
-if (sys.argv[1] == "name"):
- if (len(sys.argv) < 3):
+if (args[0] == "name"):
+ if (len(args) < 2):
properties = adapter.GetProperties()
print properties["Name"]
else:
- adapter.SetProperty("Name", sys.argv[2])
+ adapter.SetProperty("Name", args[1])
sys.exit(0)
-if (sys.argv[1] == "powered"):
- if (len(sys.argv) < 3):
+if (args[0] == "powered"):
+ if (len(args) < 2):
properties = adapter.GetProperties()
print properties["Powered"]
else:
- if (sys.argv[2] == "on"):
+ if (args[1] == "on"):
value = dbus.Boolean(1)
- elif (sys.argv[2] == "off"):
+ elif (args[1] == "off"):
value = dbus.Boolean(0)
else:
- value = dbus.Boolean(sys.argv[2])
+ value = dbus.Boolean(args[1])
adapter.SetProperty("Powered", value)
sys.exit(0)
-if (sys.argv[1] == "pairable"):
- if (len(sys.argv) < 3):
+if (args[0] == "pairable"):
+ if (len(args) < 2):
properties = adapter.GetProperties()
print properties["Pairable"]
else:
- if (sys.argv[2] == "on"):
+ if (args[1] == "on"):
value = dbus.Boolean(1)
- elif (sys.argv[2] == "off"):
+ elif (args[1] == "off"):
value = dbus.Boolean(0)
else:
- value = dbus.Boolean(sys.argv[2])
+ value = dbus.Boolean(args[1])
adapter.SetProperty("Pairable", value)
sys.exit(0)
-if (sys.argv[1] == "pairabletimeout"):
- if (len(sys.argv) < 3):
+if (args[0] == "pairabletimeout"):
+ if (len(args) < 2):
properties = adapter.GetProperties()
print properties["PairableTimeout"]
else:
- timeout = dbus.UInt32(sys.argv[2])
+ timeout = dbus.UInt32(args[1])
adapter.SetProperty("PairableTimeout", timeout)
sys.exit(0)
-if (sys.argv[1] == "discoverable"):
- if (len(sys.argv) < 3):
+if (args[0] == "discoverable"):
+ if (len(args) < 2):
properties = adapter.GetProperties()
print properties["Discoverable"]
else:
- if (sys.argv[2] == "on"):
+ if (args[1] == "on"):
value = dbus.Boolean(1)
- elif (sys.argv[2] == "off"):
+ elif (args[1] == "off"):
value = dbus.Boolean(0)
else:
- value = dbus.Boolean(sys.argv[2])
+ value = dbus.Boolean(args[1])
adapter.SetProperty("Discoverable", value)
sys.exit(0)
-if (sys.argv[1] == "discoverabletimeout"):
- if (len(sys.argv) < 3):
+if (args[0] == "discoverabletimeout"):
+ if (len(args) < 2):
properties = adapter.GetProperties()
print properties["DiscoverableTimeout"]
else:
- timeout = dbus.UInt32(sys.argv[2])
+ timeout = dbus.UInt32(args[1])
adapter.SetProperty("DiscoverableTimeout", timeout)
sys.exit(0)
-if (sys.argv[1] == "discovering"):
+if (args[0] == "discovering"):
properties = adapter.GetProperties()
print properties["Discovering"]
sys.exit(0)
diff --git a/test/test-audio b/test/test-audio
new file mode 100755
index 0000000..8b7a62d
--- /dev/null
+++ b/test/test-audio
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+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-device b/test/test-device
index f8f2d14..a04ff35 100755
--- a/test/test-device
+++ b/test/test-device
@@ -3,15 +3,29 @@
import sys
import dbus
import re
+from optparse import OptionParser, make_option
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
"org.bluez.Adapter")
-if (len(sys.argv) < 2):
+if (len(args) < 1):
print "Usage: %s <command>" % (sys.argv[0])
print ""
print " list"
@@ -22,43 +36,48 @@
print " name <address>"
print " alias <address> [alias]"
print " trusted <address> [yes/no]"
+ print " blocked <address> [yes/no]"
sys.exit(1)
-if (sys.argv[1] == "list"):
- list = adapter.ListDevices()
- print list
+if (args[0] == "list"):
+ for path in adapter.ListDevices():
+ device = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device")
+ properties = device.GetProperties()
+ print "%s %s" % (properties["Address"], properties["Alias"])
+
sys.exit(0)
-if (sys.argv[1] == "create"):
- if (len(sys.argv) < 3):
+if (args[0] == "create"):
+ if (len(args) < 2):
print "Need address parameter"
else:
- device = adapter.CreateDevice(sys.argv[2])
+ device = adapter.CreateDevice(args[1])
print device
sys.exit(0)
-if (sys.argv[1] == "remove"):
- if (len(sys.argv) < 3):
+if (args[0] == "remove"):
+ if (len(args) < 2):
print "Need address or object path parameter"
else:
try:
- path = adapter.FindDevice(sys.argv[2])
+ path = adapter.FindDevice(args[1])
except:
- path = sys.argv[2]
+ path = args[1]
adapter.RemoveDevice(path)
sys.exit(0)
-if (sys.argv[1] == "discover"):
- if (len(sys.argv) < 3):
+if (args[0] == "discover"):
+ if (len(args) < 2):
print "Need address parameter"
else:
- path = adapter.FindDevice(sys.argv[2])
+ path = adapter.FindDevice(args[1])
device = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device")
- if (len(sys.argv) < 4):
+ if (len(args) < 3):
pattern = ""
else:
- pattern = sys.argv[3]
+ pattern = args[2]
services = device.DiscoverServices(pattern);
for key in services.keys():
p = re.compile(">.*?<")
@@ -68,61 +87,81 @@
print
sys.exit(0)
-if (sys.argv[1] == "class"):
- if (len(sys.argv) < 3):
+if (args[0] == "class"):
+ if (len(args) < 2):
print "Need address parameter"
else:
- path = adapter.FindDevice(sys.argv[2])
+ path = adapter.FindDevice(args[1])
device = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device")
properties = device.GetProperties()
print "0x%06x" % (properties["Class"])
sys.exit(0)
-if (sys.argv[1] == "name"):
- if (len(sys.argv) < 3):
+if (args[0] == "name"):
+ if (len(args) < 2):
print "Need address parameter"
else:
- path = adapter.FindDevice(sys.argv[2])
+ path = adapter.FindDevice(args[1])
device = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device")
properties = device.GetProperties()
print properties["Name"]
sys.exit(0)
-if (sys.argv[1] == "alias"):
- if (len(sys.argv) < 3):
+if (args[0] == "alias"):
+ if (len(args) < 2):
print "Need address parameter"
else:
- path = adapter.FindDevice(sys.argv[2])
+ path = adapter.FindDevice(args[1])
device = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device")
- if (len(sys.argv) < 4):
+ if (len(args) < 3):
properties = device.GetProperties()
print properties["Alias"]
else:
- device.SetProperty("Alias", sys.argv[3])
+ device.SetProperty("Alias", args[2])
sys.exit(0)
-if (sys.argv[1] == "trusted"):
- if (len(sys.argv) < 3):
+if (args[0] == "trusted"):
+ if (len(args) < 2):
print "Need address parameter"
else:
- path = adapter.FindDevice(sys.argv[2])
+ path = adapter.FindDevice(args[1])
device = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device")
- if (len(sys.argv) < 4):
+ if (len(args) < 3):
properties = device.GetProperties()
print properties["Trusted"]
else:
- if (sys.argv[3] == "yes"):
+ if (args[2] == "yes"):
value = dbus.Boolean(1)
- elif (sys.argv[3] == "no"):
+ elif (args[2] == "no"):
value = dbus.Boolean(0)
else:
- value = dbus.Boolean(sys.argv[3])
+ value = dbus.Boolean(args[2])
device.SetProperty("Trusted", value)
sys.exit(0)
+if (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")
+ if (len(args) < 3):
+ properties = device.GetProperties()
+ print properties["Blocked"]
+ else:
+ if (args[2] == "yes"):
+ value = dbus.Boolean(1)
+ elif (args[2] == "no"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(args[2])
+ device.SetProperty("Blocked", value)
+ sys.exit(0)
+
print "Unknown command"
sys.exit(1)
diff --git a/test/test-discovery b/test/test-discovery
index e45bcc0..22c88c3 100755
--- a/test/test-discovery
+++ b/test/test-discovery
@@ -4,6 +4,7 @@
import dbus
import dbus.mainloop.glib
+from optparse import OptionParser, make_option
def device_found(address, properties):
print "[ " + address + " ]"
@@ -26,8 +27,20 @@
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.bluez.Manager")
- path = manager.DefaultAdapter()
- adapter = dbus.Interface(bus.get_object("org.bluez", path),
+ option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+ parser = OptionParser(option_list=option_list)
+
+ (options, args) = parser.parse_args()
+
+ if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+ else:
+ adapter_path = manager.DefaultAdapter()
+
+ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
"org.bluez.Adapter")
bus.add_signal_receiver(device_found,
diff --git a/test/test-input b/test/test-input
new file mode 100755
index 0000000..405bb59
--- /dev/null
+++ b/test/test-input
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+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)
diff --git a/test/test-nap b/test/test-nap
new file mode 100755
index 0000000..c83d928
--- /dev/null
+++ b/test/test-nap
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+import sys
+import time
+import dbus
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+server = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.NetworkServer")
+
+service = "nap"
+
+if (len(args) < 1):
+ bridge = "tether"
+else:
+ bridge = args[0]
+
+server.Register(service, bridge)
+
+print "Server for %s registered for %s" % (service, bridge)
+
+print "Press CTRL-C to disconnect"
+
+try:
+ time.sleep(1000)
+ print "Terminating connection"
+except:
+ pass
+
+server.Unregister(service)
diff --git a/test/test-network b/test/test-network
index 6f75bed..676fb30 100755
--- a/test/test-network
+++ b/test/test-network
@@ -3,25 +3,39 @@
import sys
import time
import dbus
+from optparse import OptionParser, make_option
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.bluez.Manager")
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
"org.bluez.Adapter")
-if (len(sys.argv) < 2):
+if (len(args) < 1):
print "Usage: %s <address> [service]" % (sys.argv[0])
sys.exit(1)
-address = sys.argv[1]
+address = args[0]
-if (len(sys.argv) < 3):
+if (len(args) < 2):
service = "panu"
else:
- service = sys.argv[2]
+ service = args[1]
device = adapter.FindDevice(address)
diff --git a/test/test-serial b/test/test-serial
index f6d6022..ed151dc 100755
--- a/test/test-serial
+++ b/test/test-serial
@@ -3,25 +3,38 @@
import sys
import time
import dbus
+from optparse import OptionParser, make_option
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.bluez.Manager")
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
"org.bluez.Adapter")
-if (len(sys.argv) < 2):
+if (len(args) < 1):
print "Usage: %s <address> [service]" % (sys.argv[0])
sys.exit(1)
-address = sys.argv[1]
+address = sys.argv[0]
-if (len(sys.argv) < 3):
+if (len(args) < 2):
service = "spp"
else:
- service = sys.argv[2]
+ service = args[1]
path = adapter.FindDevice(address)
diff --git a/test/test-service b/test/test-service
index e005201..dae40fc 100755
--- a/test/test-service
+++ b/test/test-service
@@ -3,25 +3,39 @@
import sys
import dbus
import time
+from optparse import OptionParser, make_option
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.FindAdapter("any")),
- "org.bluez.Service")
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
-if (len(sys.argv) < 2):
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.Adapter")
+
+if (len(args) < 1):
print "Usage: %s <command>" % (sys.argv[0])
print ""
print " addrecord <file>"
sys.exit(1)
-if (sys.argv[1] == "addrecord"):
- if (len(sys.argv) < 3):
+if (args[0] == "addrecord"):
+ if (len(args) < 2):
print "Need file parameter"
else:
- f = open(sys.argv[2])
+ f = open(args[1])
record = f.read()
f.close()
handle = adapter.AddRecord(record)
diff --git a/test/test-telephony b/test/test-telephony
index eb69511..5ef0ac8 100755
--- a/test/test-telephony
+++ b/test/test-telephony
@@ -2,16 +2,32 @@
import sys
import dbus
+from optparse import OptionParser, make_option
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
- "org.bluez.Adapter")
+
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.Adapter")
+
test = dbus.Interface(bus.get_object("org.bluez", "/org/bluez/test"),
"org.bluez.TelephonyTest")
-if len(sys.argv) < 2:
+if len(args) < 1:
print """Usage: %s <command>
connect <bdaddr>
@@ -31,127 +47,127 @@
""" % sys.argv[0]
sys.exit(1)
-if sys.argv[1] == "connect":
- if len(sys.argv) < 3:
+if args[0] == "connect":
+ if len(args) < 2:
print "Need device address parameter"
sys.exit(1)
- device = adapter.FindDevice(sys.argv[2])
+ device = adapter.FindDevice(args[1])
headset = dbus.Interface(bus.get_object("org.bluez", device),
"org.bluez.Headset")
headset.Connect()
sys.exit(0)
-if sys.argv[1] == "disconnect":
- if len(sys.argv) < 3:
+if args[0] == "disconnect":
+ if len(args) < 2:
print "Need device address parameter"
sys.exit(1)
- device = adapter.FindDevice(sys.argv[2])
+ device = adapter.FindDevice(args[1])
headset = dbus.Interface(bus.get_object("org.bluez", device),
"org.bluez.Headset")
headset.Disconnect()
sys.exit(0)
-if sys.argv[1] == "speakergain":
- if len(sys.argv) < 3:
+if args[0] == "speakergain":
+ if len(args) < 2:
print "Need device address parameter"
sys.exit(1)
- device = adapter.FindDevice(sys.argv[2])
+ device = adapter.FindDevice(args[1])
headset = dbus.Interface(bus.get_object("org.bluez", device),
"org.bluez.Headset")
- if len(sys.argv) > 3:
- headset.SetProperty('SpeakerGain', dbus.UInt16(sys.argv[3]))
+ if len(args) > 2:
+ headset.SetProperty('SpeakerGain', dbus.UInt16(args[2]))
else:
props = headset.GetProperties()
print props['SpeakerGain']
sys.exit(0)
-if sys.argv[1] == "microphonegain":
- if len(sys.argv) < 3:
+if args[0] == "microphonegain":
+ if len(args) < 2:
print "Need device address parameter"
sys.exit(1)
- device = adapter.FindDevice(sys.argv[2])
+ device = adapter.FindDevice(args[1])
headset = dbus.Interface(bus.get_object("org.bluez", device),
"org.bluez.Headset")
- if len(sys.argv) > 3:
- headset.SetProperty('MicrophoneGain', dbus.UInt16(sys.argv[3]))
+ if len(args) > 2:
+ headset.SetProperty('MicrophoneGain', dbus.UInt16(args[2]))
else:
props = headset.GetProperties()
print props['MicrophoneGain']
sys.exit(0)
-if sys.argv[1] == "play":
- if len(sys.argv) < 3:
+if args[0] == "play":
+ if len(args) < 2:
print "Need device address parameter"
sys.exit(1)
- device = adapter.FindDevice(sys.argv[2])
+ device = adapter.FindDevice(args[1])
headset = dbus.Interface(bus.get_object("org.bluez", device),
"org.bluez.Headset")
headset.Play()
sys.exit(0)
-if sys.argv[1] == "stop":
- if len(sys.argv) < 3:
+if args[0] == "stop":
+ if len(args) < 2:
print "Need device address parameter"
sys.exit(1)
- device = adapter.FindDevice(sys.argv[2])
+ device = adapter.FindDevice(args[1])
headset = dbus.Interface(bus.get_object("org.bluez", device),
"org.bluez.Headset")
headset.Stop()
sys.exit(0)
-if sys.argv[1] == "outgoing":
- if len(sys.argv) > 2:
- test.OutgoingCall(sys.argv[2])
+if args[0] == "outgoing":
+ if len(args) > 1:
+ test.OutgoingCall(args[1])
else:
print "Need number parameter"
sys.exit(0)
-if sys.argv[1] == "incoming":
- if len(sys.argv) > 2:
- test.IncomingCall(sys.argv[2])
+if args[0] == "incoming":
+ if len(args) > 1:
+ test.IncomingCall(args[1])
else:
print "Need number parameter"
sys.exit(0)
-if sys.argv[1] == "cancel":
+if args[0] == "cancel":
test.CancelCall()
sys.exit(0)
-if sys.argv[1] == "signal":
- if len(sys.argv) > 2:
- test.SignalStrength(sys.argv[2])
+if args[0] == "signal":
+ if len(args) > 1:
+ test.SignalStrength(args[1])
else:
print "Need signal strength parameter"
sys.exit(0)
-if sys.argv[1] == "battery":
- if len(sys.argv) > 2:
- test.BatteryLevel(sys.argv[2])
+if args[0] == "battery":
+ if len(args) > 1:
+ test.BatteryLevel(args[1])
else:
print "Need battery level parameter"
sys.exit(0)
-if sys.argv[1] == "roaming":
- if len(sys.argv) > 2:
- test.RoamingStatus(sys.argv[2] == "yes" or False)
+if args[0] == "roaming":
+ if len(args) > 1:
+ test.RoamingStatus(args[1] == "yes" or False)
else:
print "Need yes/no parameter"
sys.exit(0)
-if sys.argv[1] == "registration":
- if len(sys.argv) > 2:
- test.RegistrationStatus(sys.argv[2] == "yes" or False)
+if args[0] == "registration":
+ if len(args) > 1:
+ test.RegistrationStatus(args[1] == "yes" or False)
else:
print "Need yes/no parameter"
sys.exit(0)
-if sys.argv[1] == "subscriber":
- if len(sys.argv) > 2:
- test.SetSubscriberNumber(sys.argv[2])
+if args[0] == "subscriber":
+ if len(args) > 1:
+ test.SetSubscriberNumber(args[1])
else:
print "Need number parameter"
sys.exit(0)
diff --git a/common/test_textfile.c b/test/test-textfile.c
similarity index 96%
rename from common/test_textfile.c
rename to test/test-textfile.c
index 29ca493..970e9e7 100644
--- a/common/test_textfile.c
+++ b/test/test-textfile.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -65,7 +65,7 @@
sprintf(key, "00:00:00:00:00:00");
- if (textfile_del(filename, key) < 0)
+ if (textfile_del(filename, key) < 0)
fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
memset(value, 0, sizeof(value));
@@ -88,7 +88,7 @@
if (textfile_put(filename, key, value) < 0)
fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
- if (textfile_del(filename, key) < 0)
+ if (textfile_del(filename, key) < 0)
fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
str = textfile_get(filename, key);
diff --git a/tools/Android.mk b/tools/Android.mk
index c966a3b..3d21163 100755
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -10,14 +10,14 @@
avinfo.c
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_C_INCLUDES:=\
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -35,17 +35,14 @@
sdptool.c
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" -fpermissive
+ -DVERSION=\"4.69\" -fpermissive
LOCAL_C_INCLUDES:=\
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static
+ libbluetoothd libbluetooth
LOCAL_MODULE:=sdptool
@@ -64,17 +61,14 @@
LOCAL_CFLAGS:= \
-DSTORAGEDIR=\"/tmp\" \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_C_INCLUDES:=\
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -93,17 +87,14 @@
LOCAL_CFLAGS:= \
-DSTORAGEDIR=\"/tmp\" \
- -DVERSION=\"4.47\"
+ -DVERSION=\"4.69\"
LOCAL_C_INCLUDES:=\
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -121,11 +112,11 @@
l2ping.c
LOCAL_C_INCLUDES:=\
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
+ libbluetoothd libbluetooth
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := eng
@@ -146,19 +137,46 @@
hciattach_tialt.c
LOCAL_CFLAGS:= \
- -DVERSION=\"4.47\" \
+ -DVERSION=\"4.69\" \
-D__BSD_VISIBLE=1
LOCAL_C_INCLUDES:=\
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../common \
+ $(LOCAL_PATH)/../lib \
+ $(LOCAL_PATH)/../src \
LOCAL_SHARED_LIBRARIES := \
- libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
- libbluez-common-static
+ libbluetoothd libbluetooth
LOCAL_MODULE:=hciattach
include $(BUILD_EXECUTABLE)
+
+#
+# rfcomm
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ kword.c \
+ main.c \
+ parser.c \
+ lexer.c
+
+LOCAL_CFLAGS:= \
+ -DVERSION=\"4.69\" \
+ -DCONFIGDIR=\"/etc/bluetooth\" \
+ -DNEED_PPOLL
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/../src \
+ $(LOCAL_PATH)/../lib
+
+LOCAL_SHARED_LIBRARIES := \
+ libbluetooth
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE:=rfcomm
+
+include $(BUILD_EXECUTABLE)
diff --git a/tools/Makefile.am b/tools/Makefile.am
deleted file mode 100644
index 5589a5a..0000000
--- a/tools/Makefile.am
+++ /dev/null
@@ -1,106 +0,0 @@
-
-if TOOLS
-tools_programs = l2ping hcitool sdptool ciptool
-tools_manfiles = l2ping.8 hcitool.1 sdptool.1 ciptool.1
-else
-tools_programs =
-tools_manfiles =
-endif
-
-if BCCMD
-bccmd_programs = bccmd
-bccmd_manfiles = bccmd.8
-else
-bccmd_programs =
-bccmd_manfiles =
-endif
-
-if HID2HCI
-hid2hci_programs = hid2hci
-hid2hci_manfiles = hid2hci.8
-else
-hid2hci_programs =
-hid2hci_manfiles =
-endif
-
-if DFUTOOL
-dfutool_programs = dfutool
-dfutool_manfiles = dfutool.1
-else
-dfutool_programs =
-dfutool_manfiles =
-endif
-
-if USB
-usb_programs = dfubabel avctrl
-else
-usb_programs =
-endif
-
-sbin_PROGRAMS = hciattach hciconfig $(bccmd_programs) $(avctrl_programs) $(hid2hci_programs)
-
-bin_PROGRAMS = $(tools_programs) $(dfutool_programs) $(dfubabel_programs)
-
-noinst_PROGRAMS = hcieventmask hcisecfilter ppporc avinfo $(usb_programs)
-
-hcieventmask_LDADD = @BLUEZ_LIBS@
-
-hciattach_SOURCES = hciattach.c hciattach.h \
- hciattach_st.c hciattach_ti.c hciattach_tialt.c
-hciattach_LDADD = @BLUEZ_LIBS@
-
-hciconfig_SOURCES = hciconfig.c csr.h csr.c
-hciconfig_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-if TOOLS
-hcitool_SOURCES = hcitool.c
-hcitool_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-l2ping_LDADD = @BLUEZ_LIBS@
-
-sdptool_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-ciptool_LDADD = @BLUEZ_LIBS@
-
-avinfo_LDADD = @BLUEZ_LIBS@
-endif
-
-ppporc_LDADD = @BLUEZ_LIBS@
-
-if BCCMD
-bccmd_SOURCES = bccmd.c csr.h csr.c csr_hci.c \
- csr_bcsp.c csr_h4.c csr_3wire.c ubcsp.h ubcsp.c
-bccmd_LDADD = @BLUEZ_LIBS@
-if USB
-bccmd_SOURCES += csr_usb.c
-bccmd_LDADD += @USB_LIBS@
-endif
-endif
-
-if HID2HCI
-hid2hci_LDADD = @USB_LIBS@
-endif
-
-if DFUTOOL
-dfutool_SOURCES = dfutool.c dfu.h dfu.c
-dfutool_LDADD = @USB_LIBS@
-endif
-
-if USB
-dfubabel_LDADD = @USB_LIBS@
-avctrl_LDADD = @USB_LIBS@
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @USB_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-if MANPAGES
-man_MANS = hciattach.8 hciconfig.8 $(tools_manfiles) \
- $(bccmd_manfiles) $(hid2hci_manfiles) $(dfutool_manfiles)
-endif
-
-EXTRA_DIST = hciattach.8 hciconfig.8 l2ping.8 hcitool.1 sdptool.1 ciptool.1 \
- bccmd.8 avctrl.8 hid2hci.8 dfutool.1 dfubabel.1 example.psr
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/tools/avctrl.c b/tools/avctrl.c
index 7b5e685..3621a68 100644
--- a/tools/avctrl.c
+++ b/tools/avctrl.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/avinfo.c b/tools/avinfo.c
index a3cfd45..7f76c03 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -2,8 +2,8 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2006-2007 Nokia Corporation
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * 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
diff --git a/tools/bccmd.c b/tools/bccmd.c
index 0e0c28c..686e858 100644
--- a/tools/bccmd.c
+++ b/tools/bccmd.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -984,7 +984,7 @@
str = NULL;
}
- printf("// %s%s\n&%04x =", str ? "PSKEY_" : "",
+ printf("// %s%s\n&%04x =", str ? "PSKEY_" : "",
str ? str : val, pskey);
for (i = 0; i < length; i++)
printf(" %02x%02x", array[(i * 2) + 7], array[(i * 2) + 6]);
diff --git a/tools/ciptool.c b/tools/ciptool.c
index 2afa30e..edce9da 100644
--- a/tools/ciptool.c
+++ b/tools/ciptool.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr.c b/tools/csr.c
index 884f0d1..b4ea1fb 100644
--- a/tools/csr.c
+++ b/tools/csr.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr.h b/tools/csr.h
index 42bdb9f..1d70491 100644
--- a/tools/csr.h
+++ b/tools/csr.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_3wire.c b/tools/csr_3wire.c
index 34a0db9..33fcf38 100644
--- a/tools/csr_3wire.c
+++ b/tools/csr_3wire.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_bcsp.c b/tools/csr_bcsp.c
index 2c73323..e551311 100644
--- a/tools/csr_bcsp.c
+++ b/tools/csr_bcsp.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_h4.c b/tools/csr_h4.c
index 6fa326f..3371770 100644
--- a/tools/csr_h4.c
+++ b/tools/csr_h4.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_hci.c b/tools/csr_hci.c
index 7f54d55..6bd37c3 100644
--- a/tools/csr_hci.c
+++ b/tools/csr_hci.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_usb.c b/tools/csr_usb.c
index e756150..19903b0 100644
--- a/tools/csr_usb.c
+++ b/tools/csr_usb.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfu.c b/tools/dfu.c
index 0207086..39ec088 100644
--- a/tools/dfu.c
+++ b/tools/dfu.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfu.h b/tools/dfu.h
index 427cb42..7f999f4 100644
--- a/tools/dfu.h
+++ b/tools/dfu.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfubabel.c b/tools/dfubabel.c
index 498a717..612accc 100644
--- a/tools/dfubabel.c
+++ b/tools/dfubabel.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfutool.c b/tools/dfutool.c
index 055de25..16dd62e 100644
--- a/tools/dfutool.c
+++ b/tools/dfutool.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -341,7 +341,7 @@
size = st.st_size;
if (!(buf = malloc(size))) {
- perror("Unable to allocate file buffer");
+ perror("Unable to allocate file buffer");
exit(1);
}
@@ -442,7 +442,7 @@
filesize = st.st_size;
if (!(buf = malloc(filesize))) {
- perror("Unable to allocate file buffer");
+ perror("Unable to allocate file buffer");
exit(1);
}
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f750222..9bd1538 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -3,10 +3,15 @@
hciattach \- attach serial devices via UART HCI to BlueZ stack
.SH SYNOPSIS
.B hciattach
+.RB [\| \-b \|]
.RB [\| \-n \|]
.RB [\| \-p \|]
.RB [\| \-t
.IR timeout \|]
+.RB [\| \-s
+.IR speed \|]
+.RB [\| \-l \|]
+.RB [\| \-r \|]
.I tty
.IR type \||\| id
.I speed
@@ -18,6 +23,9 @@
transport interface.
.SH OPTIONS
.TP
+.B \-b
+Send break.
+.TP
.B \-n
Don't detach from controlling terminal.
.TP
@@ -27,6 +35,15 @@
.BI \-t " timeout"
Specify an initialization timeout. (Default is 5 seconds.)
.TP
+.BI \-s " speed"
+Specify an initial speed instead of the hardware default.
+.TP
+.B \-l
+List all available configurations.
+.TP
+.B \-r
+Set the HCI device into raw mode (the kernel and bluetoothd will ignore it).
+.TP
.I tty
This specifies the serial device to attach. A leading
.B /dev
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 65737f2..1e4fb89 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -144,10 +144,10 @@
return tcsetattr(fd, TCSANOW, ti);
}
-/*
+/*
* Read an HCI event from the given file descriptor.
*/
-int read_hci_event(int fd, unsigned char* buf, int size)
+int read_hci_event(int fd, unsigned char* buf, int size)
{
int remain, r;
int count = 0;
@@ -175,9 +175,9 @@
}
/* Now we read the parameters. */
- if (buf[2] < (size - 3))
+ if (buf[2] < (size - 3))
remain = buf[2];
- else
+ else
remain = size - 3;
while ((count - 3) < remain) {
@@ -190,8 +190,8 @@
return count;
}
-/*
- * Ericsson specific initialization
+/*
+ * Ericsson specific initialization
*/
static int ericsson(int fd, struct uart_t *u, struct termios *ti)
{
@@ -245,8 +245,8 @@
return 0;
}
-/*
- * Digianswer specific initialization
+/*
+ * Digianswer specific initialization
*/
static int digi(int fd, struct uart_t *u, struct termios *ti)
{
@@ -304,7 +304,7 @@
do {
res = read(fd, buf, count);
if (res != -1) {
- buf += res;
+ buf += res;
count -= res;
}
} while (count && (errno == 0 || errno == EINTR));
@@ -324,7 +324,8 @@
static void bcsp_tshy_sig_alarm(int sig)
{
unsigned char bcsp_sync_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0};
- int len, retries = 0;
+ int len;
+ static int retries = 0;
if (retries < bcsp_max_retries) {
retries++;
@@ -341,7 +342,8 @@
static void bcsp_tconf_sig_alarm(int sig)
{
unsigned char bcsp_conf_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0};
- int len, retries = 0;
+ int len;
+ static int retries = 0;
if (retries < bcsp_max_retries){
retries++;
@@ -478,8 +480,8 @@
return 0;
}
-/*
- * CSR specific initialization
+/*
+ * CSR specific initialization
* Inspired strongly by code in OpenBT and experimentations with Brainboxes
* Pcmcia card.
* Jean Tourrilhes <jt@hpl.hp.com> - 14.11.01
@@ -542,7 +544,7 @@
return -1;
}
- /* Event code 0xFF is for vendor-specific events, which is
+ /* Event code 0xFF is for vendor-specific events, which is
* what we're looking for. */
} while (resp[1] != 0xFF);
@@ -558,7 +560,7 @@
}
#endif
/* Display that to user */
- fprintf(stderr, "CSR build ID 0x%02X-0x%02X\n",
+ fprintf(stderr, "CSR build ID 0x%02X-0x%02X\n",
resp[15] & 0xFF, resp[14] & 0xFF);
/* Try to read the current speed of the CSR chip */
@@ -586,7 +588,7 @@
return -1;
}
- /* Event code 0xFF is for vendor-specific events, which is
+ /* Event code 0xFF is for vendor-specific events, which is
* what we're looking for. */
} while (resp[1] != 0xFF);
@@ -600,7 +602,7 @@
#endif
if (u->speed > 1500000) {
- fprintf(stderr, "Speed %d too high. Remaining at %d baud\n",
+ fprintf(stderr, "Speed %d too high. Remaining at %d baud\n",
u->speed, u->init_speed);
u->speed = u->init_speed;
} else if (u->speed != 57600 && uart_speed(u->speed) == B57600) {
@@ -650,8 +652,8 @@
return 0;
}
-/*
- * Silicon Wave specific initialization
+/*
+ * Silicon Wave specific initialization
* Thomas Moser <thomas.moser@tmoser.ch>
*/
static int swave(int fd, struct uart_t *u, struct termios *ti)
@@ -667,7 +669,7 @@
// Subcommand", e.g. "soft reset" to make the changes effective.
cmd[0] = HCI_COMMAND_PKT; // it's a command packet
- cmd[1] = 0x0B; // OCF 0x0B = param access set
+ cmd[1] = 0x0B; // OCF 0x0B = param access set
cmd[2] = 0xfc; // OGF bx111111 = vendor specific
cmd[3] = 0x06; // 6 bytes of data following
cmd[4] = 0x01; // param sub command
@@ -701,9 +703,9 @@
return -1;
}
- // We should wait for a "GET Event" to confirm the success of
- // the baud rate setting. Wait some time before reading. Better:
- // read with timeout, parse data
+ // We should wait for a "GET Event" to confirm the success of
+ // the baud rate setting. Wait some time before reading. Better:
+ // read with timeout, parse data
// until correct answer, else error handling ... todo ...
nanosleep(&tm, NULL);
@@ -747,7 +749,7 @@
// now the uart baud rate on the silicon wave module is set and effective.
// change our own baud rate as well. Then there is a reset event comming in
// on the *new* baud rate. This is *undocumented*! The packet looks like this:
- // 04 FF 01 0B (which would make that a confirmation of 0x0B = "Param
+ // 04 FF 01 0B (which would make that a confirmation of 0x0B = "Param
// subcommand class". So: change to new baud rate, read with timeout, parse
// data, error handling. BTW: all param access in Silicon Wave is done this way.
// Maybe this code would belong in a seperate file, or at least code reuse...
@@ -1093,10 +1095,14 @@
}
/* Initialize UART driver */
-static int init_uart(char *dev, struct uart_t *u, int send_break)
+static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
{
struct termios ti;
int fd, i;
+ unsigned long flags = 0;
+
+ if (raw)
+ flags |= 1 << HCI_UART_RAW_DEVICE;
fd = open(dev, O_RDWR | O_NOCTTY);
if (fd < 0) {
@@ -1155,6 +1161,11 @@
return -1;
}
+ if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
+ perror("Can't set UART flags");
+ return -1;
+ }
+
if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
perror("Can't set device");
return -1;
@@ -1170,14 +1181,14 @@
{
printf("hciattach - HCI UART driver initialization utility\n");
printf("Usage:\n");
- printf("\thciattach [-n] [-p] [-b] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");
+ printf("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");
printf("\thciattach -l\n");
}
int main(int argc, char *argv[])
{
struct uart_t *u = NULL;
- int detach, printpid, opt, i, n, ld, err;
+ int detach, printpid, raw, opt, i, n, ld, err;
int to = 10;
int init_speed = 0;
int send_break = 0;
@@ -1189,8 +1200,9 @@
detach = 1;
printpid = 0;
+ raw = 0;
- while ((opt=getopt(argc, argv, "bnpt:s:l")) != EOF) {
+ while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) {
switch(opt) {
case 'b':
send_break = 1;
@@ -1219,6 +1231,10 @@
}
exit(0);
+ case 'r':
+ raw = 1;
+ break;
+
default:
usage();
exit(1);
@@ -1257,7 +1273,7 @@
fprintf(stderr, "Unknown device type or id\n");
exit(1);
}
-
+
break;
case 2:
@@ -1296,9 +1312,9 @@
alarm(to);
bcsp_max_retries = to;
- n = init_uart(dev, u, send_break);
+ n = init_uart(dev, u, send_break, raw);
if (n < 0) {
- perror("Can't initialize device");
+ perror("Can't initialize device");
exit(1);
}
diff --git a/tools/hciattach.h b/tools/hciattach.h
index e772211..c0b80a1 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -30,6 +30,8 @@
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
#define HCIUARTGETDEVICE _IOR('U', 202, int)
+#define HCIUARTSETFLAGS _IOW('U', 203, int)
+#define HCIUARTGETFLAGS _IOR('U', 204, int)
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
@@ -37,6 +39,8 @@
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_RAW_DEVICE 0
+
int read_hci_event(int fd, unsigned char* buf, int size);
int set_speed(int fd, struct termios *ti, int speed);
diff --git a/tools/hciattach_st.c b/tools/hciattach_st.c
index e2363bf..dbb7c47 100644
--- a/tools/hciattach_st.c
+++ b/tools/hciattach_st.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -140,7 +140,7 @@
return -errno;
}
- found_fw_file = 0;
+ found_fw_file = 0;
while (1) {
d = readdir(dir);
if (!d)
@@ -203,14 +203,14 @@
int len;
int err;
- /* Hci_Cmd_Ericsson_Read_Revision_Information */
+ /* Hci_Cmd_Ericsson_Read_Revision_Information */
len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf));
if (len < 0)
return -1;
printf("%s\n", buf);
- /* HCI_Read_Local_Version_Information */
+ /* HCI_Read_Local_Version_Information */
len = do_command(dd, 0x04, 0x0001, NULL, 0, buf, sizeof(buf));
if (len < 0)
return -1;
@@ -219,7 +219,7 @@
err = load_file(dd, version, ".ptc");
if (err < 0) {
- if (err == -ENOENT)
+ if (err == -ENOENT)
fprintf(stderr, "No ROM patch file loaded.\n");
else
return -1;
@@ -227,7 +227,7 @@
err = load_file(dd, buf[2] << 8 | buf[1], ".ssf");
if (err < 0) {
- if (err == -ENOENT)
+ if (err == -ENOENT)
fprintf(stderr, "No static settings file loaded.\n");
else
return -1;
@@ -237,7 +237,7 @@
cmd[1] = 0x06;
bacpy((bdaddr_t *) (cmd + 2), bdaddr);
- /* Hci_Cmd_ST_Store_In_NVDS */
+ /* Hci_Cmd_ST_Store_In_NVDS */
len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf));
if (len < 0)
return -1;
diff --git a/tools/hciattach_ti.c b/tools/hciattach_ti.c
index e169f89..7627bc1 100644
--- a/tools/hciattach_ti.c
+++ b/tools/hciattach_ti.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -446,7 +446,7 @@
memset(resp,'\0', 100);
- /* It is possible to get software version with manufacturer specific
+ /* It is possible to get software version with manufacturer specific
HCI command HCI_VS_TI_Version_Number. But the only thing you get more
is if this is point-to-point or point-to-multipoint module */
diff --git a/tools/hciattach_tialt.c b/tools/hciattach_tialt.c
index 325e006..e4ad995 100644
--- a/tools/hciattach_tialt.c
+++ b/tools/hciattach_tialt.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -68,10 +68,10 @@
/* Read reply. */
FAILIF(read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)) < 0,
"Failed to read response");
-
+
/* Parse speed-change reply */
FAILIF(resp.uart_prefix != HCI_EVENT_PKT,
- "Error in response: not an event packet, but 0x%02x!\n",
+ "Error in response: not an event packet, but 0x%02x!\n",
resp.uart_prefix);
FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE, /* event must be event-complete */
@@ -135,7 +135,7 @@
fprintf(stdout, "Opening firmware file: %s\n", firmware);
- FAILIF(fw < 0,
+ FAILIF(fw < 0,
"Could not open firmware file %s: %s (%d).\n",
firmware, strerror(errno), errno);
@@ -151,17 +151,17 @@
break;
FAILIF(nr != sizeof(cmdp), "Could not read H4 + HCI header!\n");
FAILIF(*cmdp != HCI_COMMAND_PKT, "Command is not an H4 command packet!\n");
-
+
FAILIF(read(fw, data, cmd->plen) != cmd->plen,
"Could not read %d bytes of data for command with opcode %04x!\n",
cmd->plen,
cmd->opcode);
-
+
{
int nw;
#if 0
- fprintf(stdout, "\topcode 0x%04x (%d bytes of data).\n",
- cmd->opcode,
+ fprintf(stdout, "\topcode 0x%04x (%d bytes of data).\n",
+ cmd->opcode,
cmd->plen);
#endif
struct iovec iov_cmd[2];
@@ -170,18 +170,18 @@
iov_cmd[1].iov_base = data;
iov_cmd[1].iov_len = cmd->plen;
nw = writev(fd, iov_cmd, 2);
- FAILIF(nw != (int) sizeof(cmd) + cmd->plen,
+ FAILIF(nw != (int) sizeof(cmd) + cmd->plen,
"Could not send entire command (sent only %d bytes)!\n",
nw);
}
/* Wait for response */
- if (read_command_complete(fd,
+ if (read_command_complete(fd,
cmd->opcode,
cmd->plen) < 0) {
return -1;
}
-
+
} while(1);
fprintf(stdout, "Firmware upload successful.\n");
@@ -198,7 +198,7 @@
memset(resp,'\0', 100);
- /* It is possible to get software version with manufacturer specific
+ /* It is possible to get software version with manufacturer specific
HCI command HCI_VS_TI_Version_Number. But the only thing you get more
is if this is point-to-point or point-to-multipoint module */
diff --git a/tools/hciconfig.8 b/tools/hciconfig.8
index 13f52c6..35956c4 100644
--- a/tools/hciconfig.8
+++ b/tools/hciconfig.8
@@ -10,6 +10,7 @@
.br
.B hciconfig
.RB [\| \-a \|]
+.B hciX
.RI [\| command
.RI [\| "command parameters" \|]\|]
diff --git a/tools/hciconfig.c b/tools/hciconfig.c
index a89aed1..87dd127 100644
--- a/tools/hciconfig.c
+++ b/tools/hciconfig.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -453,7 +453,7 @@
hci_close_dev(dd);
}
-/*
+/*
* see http://www.bluetooth.org/assigned-numbers/baseband.htm --- all
* strings are reproduced verbatim
*/
@@ -562,7 +562,7 @@
break;
case 5: /* peripheral */ {
static char cls_str[48];
-
+
cls_str[0] = '\0';
switch(minor & 48) {
@@ -944,7 +944,8 @@
lmpver = lmp_vertostr(ver.hci_ver);
print_dev_hdr(&di);
- printf("\tHCI Ver: %s (0x%x) HCI Rev: 0x%x LMP Ver: %s (0x%x) LMP Subver: 0x%x\n"
+ printf("\tHCI Version: %s (0x%x) Revision: 0x%x\n"
+ "\tLMP Version: %s (0x%x) Subversion: 0x%x\n"
"\tManufacturer: %s (%d)\n",
hciver ? hciver : "n/a", ver.hci_ver, ver.hci_rev,
lmpver ? lmpver : "n/a", ver.lmp_ver, ver.lmp_subver,
@@ -980,7 +981,7 @@
} else {
int8_t level;
- if (hci_read_inquiry_transmit_power_level(dd, &level, 1000) < 0) {
+ if (hci_read_inq_response_tx_power_level(dd, &level, 1000) < 0) {
fprintf(stderr, "Can't read inquiry transmit power level on hci%d: %s (%d)\n",
hdev, strerror(errno), errno);
exit(1);
@@ -1127,7 +1128,11 @@
}
break;
case 0x0a:
- printf("\tTX power level: %d\n", *((uint8_t *) ptr));
+ printf("\tTX power level: %d\n", *((int8_t *) ptr));
+ break;
+ case 0x10:
+ printf("\tDevice ID with %d bytes data\n",
+ len - 1);
break;
default:
printf("\tUnknown type 0x%02x with %d bytes data\n",
@@ -1375,7 +1380,7 @@
exit(1);
}
print_dev_hdr(&di);
-
+
timeout = btohs(rp.timeout);
printf("\tPage timeout: %u slots (%.2f ms)\n",
timeout, (float)timeout * 0.625);
@@ -1572,6 +1577,59 @@
return;
}
+static void cmd_block(int ctl, int hdev, char *opt)
+{
+ bdaddr_t bdaddr;
+ 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);
+ }
+
+ str2ba(opt, &bdaddr);
+
+ if (ioctl(dd, HCIBLOCKADDR, &bdaddr) < 0) {
+ perror("ioctl(HCIBLOCKADDR)");
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_unblock(int ctl, int hdev, char *opt)
+{
+ bdaddr_t bdaddr;
+ 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 (!strcasecmp(opt, "all"))
+ bacpy(&bdaddr, BDADDR_ANY);
+ else
+ str2ba(opt, &bdaddr);
+
+ if (ioctl(dd, HCIUNBLOCKADDR, &bdaddr) < 0) {
+ perror("ioctl(HCIUNBLOCKADDR)");
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+}
+
static void print_dev_hdr(struct hci_dev_info *di)
{
static int hdr = -1;
@@ -1583,10 +1641,12 @@
ba2str(&di->bdaddr, addr);
- printf("%s:\tType: %s\n", di->name, hci_dtypetostr(di->type) );
- printf("\tBD Address: %s ACL MTU: %d:%d SCO MTU: %d:%d\n",
- addr, di->acl_mtu, di->acl_pkts,
- di->sco_mtu, di->sco_pkts);
+ printf("%s:\tType: %s Bus: %s\n", di->name,
+ hci_typetostr(di->type >> 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,
+ di->sco_mtu, di->sco_pkts);
}
static void print_dev_info(int ctl, struct hci_dev_info *di)
@@ -1666,6 +1726,8 @@
{ "features", cmd_features, 0, "Display device features" },
{ "version", cmd_version, 0, "Display version information" },
{ "revision", cmd_revision, 0, "Display revision information" },
+ { "block", cmd_block, "<bdaddr>", "Add a device to the blacklist" },
+ { "unblock", cmd_unblock, "<bdaddr>", "Remove a device from the blacklist" },
{ NULL, NULL, 0 }
};
diff --git a/tools/hcieventmask.c b/tools/hcieventmask.c
index 0976e1f..37d1d0c 100644
--- a/tools/hcieventmask.c
+++ b/tools/hcieventmask.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/hcisecfilter.c b/tools/hcisecfilter.c
index b3034da..9ad4ce0 100644
--- a/tools/hcisecfilter.c
+++ b/tools/hcisecfilter.c
@@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -121,7 +121,7 @@
hci_set_bit(OCF_READ_AFH_MODE, ocf_mask);
hci_set_bit(OCF_READ_EXT_INQUIRY_RESPONSE, ocf_mask);
hci_set_bit(OCF_READ_SIMPLE_PAIRING_MODE, ocf_mask);
- hci_set_bit(OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL, ocf_mask);
+ hci_set_bit(OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, ocf_mask);
hci_set_bit(OCF_READ_DEFAULT_ERROR_DATA_REPORTING, ocf_mask);
printf("OGF_HOST_CTL: { 0x%08x, 0x%08x, 0x%08x, 0x%02x }\n",
diff --git a/tools/hcitool.c b/tools/hcitool.c
index e8b5dd0..a91cbdf 100644
--- a/tools/hcitool.c
+++ b/tools/hcitool.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -111,6 +111,7 @@
bt_free(str);
}
+ free(cl);
return 0;
}
@@ -134,9 +135,12 @@
}
for (i = 0; i < cl->conn_num; i++, ci++)
- if (!bacmp((bdaddr_t *) arg, &ci->bdaddr))
+ if (!bacmp((bdaddr_t *) arg, &ci->bdaddr)) {
+ free(cl);
return 1;
+ }
+ free(cl);
return 0;
}
@@ -505,7 +509,6 @@
uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
int num_rsp, length, flags;
uint8_t cls[3], features[8];
- uint16_t handle;
char addr[18], name[249], oui[9], *comp, *tmp;
struct hci_version version;
struct hci_dev_info di;
@@ -605,6 +608,8 @@
printf("\n");
for (i = 0; i < num_rsp; i++) {
+ uint16_t handle = 0;
+
if (!refresh) {
memset(name, 0, sizeof(name));
tmp = get_device_name(&di.bdaddr, &(info+i)->bdaddr);
@@ -2349,6 +2354,240 @@
hci_close_dev(dd);
}
+static int print_advertising_devices(int dd)
+{
+ unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
+ struct hci_filter nf, of;
+ socklen_t olen;
+ hci_event_hdr *hdr;
+ int num, len;
+
+ olen = sizeof(of);
+ if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0) {
+ printf("Could not get socket options\n");
+ return -1;
+ }
+
+ hci_filter_clear(&nf);
+ hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
+ hci_filter_set_event(EVT_LE_META_EVENT, &nf);
+
+ if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
+ printf("Could not set socket options\n");
+ return -1;
+ }
+
+ /* Wait for 10 report events */
+ num = 10;
+ while (num--) {
+ evt_le_meta_event *meta;
+ le_advertising_info *info;
+ char addr[18];
+
+ while ((len = read(dd, buf, sizeof(buf))) < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ goto done;
+ }
+
+ hdr = (void *) (buf + 1);
+ ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
+ len -= (1 + HCI_EVENT_HDR_SIZE);
+
+ meta = (void *) ptr;
+
+ if (meta->subevent != 0x02)
+ goto done;
+
+ /* Ignoring multiple reports */
+ info = (le_advertising_info *) (meta->data + 1);
+ ba2str(&info->bdaddr, addr);
+ printf("%s\n", addr);
+ }
+
+done:
+ setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of));
+
+ if (len < 0)
+ return -1;
+
+ return 0;
+}
+
+static struct option lescan_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static const char *lescan_help =
+ "Usage:\n"
+ "\tlescan\n";
+
+static void cmd_lescan(int dev_id, int argc, char **argv)
+{
+ int err, opt, dd;
+
+ for_each_opt(opt, lescan_options, NULL) {
+ switch (opt) {
+ default:
+ printf("%s", lescan_help);
+ return;
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("Could not open device");
+ exit(1);
+ }
+
+ err = hci_le_set_scan_parameters(dd, 0x01, htobs(0x0010), htobs(0x0010),
+ 0x00, 0x00);
+ if (err < 0) {
+ perror("Set scan parameters failed");
+ exit(1);
+ }
+
+ err = hci_le_set_scan_enable(dd, 0x01, 0x00);
+ if (err < 0) {
+ perror("Enable scan failed");
+ exit(1);
+ }
+
+ printf("LE Scan ...\n");
+
+ err = print_advertising_devices(dd);
+ if (err < 0) {
+ perror("Could not receive advertising events");
+ exit(1);
+ }
+
+ err = hci_le_set_scan_enable(dd, 0x00, 0x00);
+ if (err < 0) {
+ perror("Disable scan failed");
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+}
+
+static struct option lecc_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static const char *lecc_help =
+ "Usage:\n"
+ "\tlecc <bdaddr>\n";
+
+static void cmd_lecc(int dev_id, int argc, char **argv)
+{
+ int err, opt, dd;
+ bdaddr_t bdaddr;
+ uint16_t interval, latency, max_ce_length, max_interval, min_ce_length;
+ uint16_t min_interval, supervision_timeout, window, handle;
+ uint8_t initiator_filter, own_bdaddr_type, peer_bdaddr_type;
+
+ for_each_opt(opt, lecc_options, NULL) {
+ switch (opt) {
+ default:
+ printf("%s", lecc_help);
+ return;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf("%s", lecc_help);
+ return;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("Could not open device");
+ exit(1);
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ interval = htobs(0x0004);
+ window = htobs(0x0004);
+ initiator_filter = 0x00;
+ peer_bdaddr_type = 0x00;
+ own_bdaddr_type = 0x00;
+ min_interval = htobs(0x000F);
+ max_interval = htobs(0x000F);
+ latency = htobs(0x0000);
+ supervision_timeout = htobs(0x0C80);
+ min_ce_length = htobs(0x0001);
+ max_ce_length = htobs(0x0001);
+
+ err = hci_le_create_conn(dd, interval, window, initiator_filter,
+ peer_bdaddr_type, bdaddr, own_bdaddr_type, min_interval,
+ max_interval, latency, supervision_timeout,
+ min_ce_length, max_ce_length, &handle, 25000);
+ if (err < 0) {
+ perror("Could not create connection");
+ exit(1);
+ }
+
+ printf("Connection handle %d\n", handle);
+
+ hci_close_dev(dd);
+}
+
+static struct option ledc_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static const char *ledc_help =
+ "Usage:\n"
+ "\tledc <handle> [reason]\n";
+
+static void cmd_ledc(int dev_id, int argc, char **argv)
+{
+ int err, opt, dd;
+ uint16_t handle;
+ uint8_t reason;
+
+ for_each_opt(opt, ledc_options, NULL) {
+ switch (opt) {
+ default:
+ printf("%s", ledc_help);
+ return;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf("%s", ledc_help);
+ return;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("Could not open device");
+ exit(1);
+ }
+
+ handle = atoi(argv[0]);
+
+ reason = (argc > 1) ? atoi(argv[1]) : HCI_OE_USER_ENDED_CONNECTION;
+
+ err = hci_disconnect(dd, handle, reason, 10000);
+ if (err < 0) {
+ perror("Could not disconnect");
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+}
+
static struct {
char *cmd;
void (*func)(int dev_id, int argc, char **argv);
@@ -2378,6 +2617,9 @@
{ "key", cmd_key, "Change connection link key" },
{ "clkoff", cmd_clkoff, "Read clock offset" },
{ "clock", cmd_clock, "Read local or remote clock" },
+ { "lescan", cmd_lescan, "Start LE scan" },
+ { "lecc", cmd_lecc, "Create a LE Connection", },
+ { "ledc", cmd_ledc, "Disconnect a LE Connection", },
{ NULL, NULL, 0 }
};
diff --git a/tools/hid2hci.c b/tools/hid2hci.c
index 11d707f..a640772 100644
--- a/tools/hid2hci.c
+++ b/tools/hid2hci.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/rfcomm/kword.c b/tools/kword.c
similarity index 95%
rename from rfcomm/kword.c
rename to tools/kword.c
index 659f293..62e24fe 100644
--- a/rfcomm/kword.c
+++ b/tools/kword.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/rfcomm/kword.h b/tools/kword.h
similarity index 91%
rename from rfcomm/kword.h
rename to tools/kword.h
index ccc0cc7..81a2a88 100644
--- a/rfcomm/kword.h
+++ b/tools/kword.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
int type;
};
-extern struct keyword_t rfcomm_keyword[];
+extern struct keyword_t rfcomm_keyword[];
int rfcomm_find_keyword(struct keyword_t *keyword, char *string);
diff --git a/tools/l2ping.c b/tools/l2ping.c
index 55597cc..29fb3d0 100644
--- a/tools/l2ping.c
+++ b/tools/l2ping.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -240,6 +240,8 @@
id = ident;
}
stat(0);
+ free(send_buf);
+ free(recv_buf);
return;
error:
diff --git a/rfcomm/lexer.c b/tools/lexer.c
similarity index 100%
rename from rfcomm/lexer.c
rename to tools/lexer.c
diff --git a/rfcomm/lexer.l b/tools/lexer.l
similarity index 96%
rename from rfcomm/lexer.l
rename to tools/lexer.l
index e15c8ab..ff9ce81 100644
--- a/rfcomm/lexer.l
+++ b/tools/lexer.l
@@ -3,7 +3,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/rfcomm/main.c b/tools/main.c
similarity index 98%
rename from rfcomm/main.c
rename to tools/main.c
index ed82432..6800445 100644
--- a/rfcomm/main.c
+++ b/tools/main.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -118,7 +118,7 @@
printf("rfcomm%d: %s channel %d %s %s\n",
di->id, addr, di->channel,
- rfcomm_state[di->state],
+ rfcomm_state[di->state],
di->flags ? rfcomm_flagstostr(di->flags) : "");
}
@@ -139,11 +139,13 @@
if (ioctl(ctl, RFCOMMGETDEVLIST, (void *) dl) < 0) {
perror("Can't get device list");
+ free(dl);
exit(1);
}
for (i = 0; i < dl->dev_num; i++)
print_dev_info(di + i);
+ free(dl);
}
static int create_dev(int ctl, int dev, uint32_t flags, bdaddr_t *bdaddr, int argc, char **argv)
@@ -249,12 +251,14 @@
if (ioctl(ctl, RFCOMMGETDEVLIST, (void *) dl) < 0) {
perror("Can't get device list");
+ free(dl);
exit(1);
}
for (i = 0; i < dl->dev_num; i++)
release_dev(ctl, (di + i)->id, 0);
+ free(dl);
return 0;
}
@@ -713,7 +717,7 @@
"\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-f, --config [file] Specify alternate config file\n"
"\t-a Show all devices (default)\n"
"\n");
@@ -739,7 +743,7 @@
{ 0, 0, 0, 0 }
};
-int main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
bdaddr_t bdaddr;
int i, opt, ctl, dev_id, show_all = 0;
diff --git a/rfcomm/parser.c b/tools/parser.c
similarity index 100%
rename from rfcomm/parser.c
rename to tools/parser.c
diff --git a/rfcomm/parser.h b/tools/parser.h
similarity index 100%
rename from rfcomm/parser.h
rename to tools/parser.h
diff --git a/rfcomm/parser.y b/tools/parser.y
similarity index 97%
rename from rfcomm/parser.y
rename to tools/parser.y
index c550e2f..96e6a56 100644
--- a/rfcomm/parser.y
+++ b/tools/parser.y
@@ -3,7 +3,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/tools/ppporc.c b/tools/ppporc.c
index ea42c0c..ca44b40 100644
--- a/tools/ppporc.c
+++ b/tools/ppporc.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -147,7 +147,7 @@
p[0].fd = 0;
p[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
-
+
p[1].fd = fd;
p[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
@@ -156,7 +156,7 @@
while (!__io_canceled) {
p[0].revents = 0;
p[1].revents = 0;
-
+
err = poll(p, 2, -1);
if (err < 0)
break;
diff --git a/rfcomm/rfcomm.1 b/tools/rfcomm.1
similarity index 100%
rename from rfcomm/rfcomm.1
rename to tools/rfcomm.1
diff --git a/rfcomm/rfcomm.conf b/tools/rfcomm.conf
similarity index 100%
rename from rfcomm/rfcomm.conf
rename to tools/rfcomm.conf
diff --git a/tools/sdptool.c b/tools/sdptool.c
index 46ff101..6cf3fdb 100644
--- a/tools/sdptool.c
+++ b/tools/sdptool.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
* Copyright (C) 2002-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
@@ -322,9 +322,9 @@
{ 0x1303, "VideoSource", NULL, 0 },
{ 0x1304, "VideoSink", NULL, 0 },
{ 0x1305, "VideoDistribution", NULL, 0 },
- { 0x1400, "MDP", NULL, 0 },
- { 0x1401, "MDPSource", NULL, 0 },
- { 0x1402, "MDPSink", NULL, 0 },
+ { 0x1400, "HDP", NULL, 0 },
+ { 0x1401, "HDPSource", NULL, 0 },
+ { 0x1402, "HDPSink", NULL, 0 },
{ 0x2112, "AppleAgent", NULL, 0 },
};
@@ -513,14 +513,16 @@
*/
static void print_tree_attr_func(void *value, void *userData)
{
- sdp_data_t *sdpdata = NULL;
+ sdp_data_t *sdpdata = value;
uint16_t attrId;
struct service_context *service = (struct service_context *) userData;
struct attrib_context context;
struct attrib_def *attrDef = NULL;
int i;
- sdpdata = (sdp_data_t *)value;
+ if (!sdpdata)
+ return;
+
attrId = sdpdata->attrId;
/* Search amongst the generic attributes */
for (i = 0; i < attrib_max; i++)
@@ -549,10 +551,7 @@
context.attrib = attrDef;
context.member_index = 0;
/* Parse attribute members */
- if (sdpdata)
- sdp_data_printf(sdpdata, &context, 2);
- else
- printf(" NULL value\n");
+ sdp_data_printf(sdpdata, &context, 2);
/* Update service */
service->service = context.service;
}
@@ -723,6 +722,9 @@
struct attrib_def *def = NULL;
int i;
+ if (!data)
+ return;
+
/* Search amongst the generic attributes */
for (i = 0; i < attrib_max; i++)
if (attrib_names[i].num == data->attrId) {
@@ -735,10 +737,7 @@
else
printf("\tAttribute 0x%04x\n", data->attrId);
- if (data)
- print_raw_data(data, 2);
- else
- printf(" NULL value\n");
+ print_raw_data(data, 2);
}
static void print_raw_attr(sdp_record_t *rec)
@@ -753,7 +752,7 @@
* Set attributes with single values in SDP record
* Jean II
*/
-static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value)
+static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value)
{
sdp_list_t *attrid_list;
uint32_t range = 0x0000ffff;
@@ -783,7 +782,7 @@
sdp_attr_add_new(rec, attrib, SDP_UUID16, &value_uuid.value.uuid16);
} else if (!strncasecmp(value, "0x", 2)) {
/* Int */
- uint32_t value_int;
+ uint32_t value_int;
value_int = strtoul(value + 2, NULL, 16);
printf("Adding attrib 0x%X int 0x%X to record 0x%X\n",
attrib, value_int, handle);
@@ -811,7 +810,7 @@
{ 0, 0, 0, 0 }
};
-static const char *set_help =
+static const char *set_help =
"Usage:\n"
"\tget record_handle attrib_id attrib_value\n";
@@ -949,7 +948,7 @@
{ 0, 0, 0, 0 }
};
-static const char *seq_help =
+static const char *seq_help =
"Usage:\n"
"\tget record_handle attrib_id attrib_values\n";
@@ -1688,7 +1687,7 @@
sdp_record_t record;
uint8_t u8 = si->channel? si->channel : 8;
uint16_t u16 = 0x31;
- sdp_data_t *channel, *features;
+ sdp_data_t *channel, *features;
int ret = 0;
memset((void *)&record, 0, sizeof(sdp_record_t));
@@ -1832,8 +1831,6 @@
uint8_t chan = si->channel ? si->channel : 19;
sdp_data_t *channel;
uint8_t formats[] = {0x01};
- void *dtds[sizeof(formats)], *values[sizeof(formats)];
- int i;
uint8_t dtd = SDP_UINT8;
sdp_data_t *sflist;
int ret = 0;
@@ -2255,7 +2252,7 @@
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[] = {
+ const uint8_t hid_spec[] = {
0x05, 0x01, // usage page
0x09, 0x06, // keyboard
0xa1, 0x01, // key codes
@@ -2268,14 +2265,14 @@
0x75, 0x01, // input data variable absolute
0x95, 0x08, // report count
0x81, 0x02, // report size
- 0x75, 0x08,
- 0x95, 0x01,
- 0x81, 0x01,
- 0x75, 0x01,
+ 0x75, 0x08,
+ 0x95, 0x01,
+ 0x81, 0x01,
+ 0x75, 0x01,
0x95, 0x05,
0x05, 0x08,
0x19, 0x01,
- 0x29, 0x05,
+ 0x29, 0x05,
0x91, 0x02,
0x75, 0x03,
0x95, 0x01,
@@ -3531,7 +3528,7 @@
{ 0, 0, 0, 0 }
};
-static const char *add_help =
+static const char *add_help =
"Usage:\n"
"\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
@@ -3596,7 +3593,7 @@
sdp_session_t *sess;
sdp_record_t *rec;
- if (!arg) {
+ if (!arg) {
printf("Record handle was not specified.\n");
return -1;
}
@@ -3635,7 +3632,7 @@
{ 0, 0, 0, 0 }
};
-static const char *del_help =
+static const char *del_help =
"Usage:\n"
"\tdel record_handle\n";
@@ -3776,7 +3773,7 @@
{ 0, 0, 0, 0 }
};
-static const char *browse_help =
+static const char *browse_help =
"Usage:\n"
"\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n";
@@ -3842,7 +3839,7 @@
{ 0, 0, 0, 0}
};
-static const char *search_help =
+static const char *search_help =
"Usage:\n"
"\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n"
"SERVICE is a name (string) or UUID (0x1002)\n";
@@ -4001,7 +3998,7 @@
{ 0, 0, 0, 0 }
};
-static const char *records_help =
+static const char *records_help =
"Usage:\n"
"\trecords [--tree] [--raw] [--xml] bdaddr\n";
@@ -4071,7 +4068,7 @@
{ 0, 0, 0, 0 }
};
-static const char *get_help =
+static const char *get_help =
"Usage:\n"
"\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n";
diff --git a/tracer/main.c b/tracer/main.c
new file mode 100644
index 0000000..0806ffe
--- /dev/null
+++ b/tracer/main.c
@@ -0,0 +1,152 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#include <glib.h>
+
+#ifdef HAVE_CAPNG
+#include <cap-ng.h>
+#endif
+
+static GMainLoop *event_loop;
+
+static void sig_term(int sig)
+{
+ g_main_loop_quit(event_loop);
+}
+
+static gboolean option_detach = TRUE;
+static gboolean option_debug = FALSE;
+
+static GOptionEntry options[] = {
+ { "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
+ G_OPTION_ARG_NONE, &option_detach,
+ "Don't run as daemon in background" },
+ { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
+ "Enable debug information output" },
+ { NULL },
+};
+
+static void debug(const char *format, ...)
+{
+ va_list ap;
+
+ if (!option_debug)
+ return;
+
+ va_start(ap, format);
+
+ vsyslog(LOG_DEBUG, format, ap);
+
+ va_end(ap);
+}
+
+static void sig_debug(int sig)
+{
+ option_debug = !option_debug;
+}
+
+int main(int argc, char *argv[])
+{
+ GOptionContext *context;
+ GError *err = NULL;
+ struct sigaction sa;
+
+#ifdef HAVE_CAPNG
+ /* Drop capabilities */
+ capng_clear(CAPNG_SELECT_BOTH);
+ capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+ CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
+ CAP_NET_RAW, CAP_IPC_LOCK, -1);
+ capng_apply(CAPNG_SELECT_BOTH);
+#endif
+
+ context = g_option_context_new(NULL);
+ g_option_context_add_main_entries(context, options, NULL);
+
+ if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
+ if (err != NULL) {
+ g_printerr("%s\n", err->message);
+ g_error_free(err);
+ } else
+ g_printerr("An unknown error occurred\n");
+ exit(1);
+ }
+
+ g_option_context_free(context);
+
+ if (option_detach == TRUE) {
+ if (daemon(0, 0)) {
+ perror("Can't start daemon");
+ exit(1);
+ }
+ }
+
+ umask(0077);
+
+ openlog("hcitrace", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
+
+ syslog(LOG_INFO, "HCI trace deamon %s", VERSION);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_debug;
+ sigaction(SIGUSR2, &sa, NULL);
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sa, NULL);
+
+ if (option_debug == TRUE) {
+ syslog(LOG_INFO, "Enabling debug information");
+ }
+
+ event_loop = g_main_loop_new(NULL, FALSE);
+
+ debug("Entering main loop");
+
+ g_main_loop_run(event_loop);
+
+ g_main_loop_unref(event_loop);
+
+ syslog(LOG_INFO, "Exit");
+
+ closelog();
+
+ return 0;
+}