summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
committerUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
commit809ce20070e58fb9fea39b56b693e422d32cbe5e (patch)
treea89ca67895981a4e1347532a1eab16f878438d99
downloadbluez-809ce20070e58fb9fea39b56b693e422d32cbe5e.tar.gz
external/bluez utils-3.35upstream/utils-3.35
-rw-r--r--utils/AUTHORS31
-rw-r--r--utils/COPYING340
-rw-r--r--utils/COPYING.LIB504
-rw-r--r--utils/ChangeLog803
-rw-r--r--utils/INSTALL236
-rw-r--r--utils/Makefile.am9
-rw-r--r--utils/Makefile.in663
-rw-r--r--utils/NEWS0
-rw-r--r--utils/README40
-rw-r--r--utils/acinclude.m4334
-rw-r--r--utils/aclocal.m47655
-rw-r--r--utils/audio/Makefile.am62
-rw-r--r--utils/audio/Makefile.in774
-rw-r--r--utils/audio/a2dp.c1470
-rw-r--r--utils/audio/a2dp.h144
-rw-r--r--utils/audio/asound.conf7
-rw-r--r--utils/audio/audio-api.txt311
-rw-r--r--utils/audio/audio.conf41
-rw-r--r--utils/audio/avdtp.c2882
-rw-r--r--utils/audio/avdtp.h268
-rw-r--r--utils/audio/control.c949
-rw-r--r--utils/audio/control.h35
-rw-r--r--utils/audio/ctl_bluetooth.c356
-rw-r--r--utils/audio/device.c435
-rw-r--r--utils/audio/device.h83
-rw-r--r--utils/audio/gateway.c34
-rw-r--r--utils/audio/gateway.h34
-rw-r--r--utils/audio/gsta2dpsink.c701
-rw-r--r--utils/audio/gsta2dpsink.h83
-rw-r--r--utils/audio/gstavdtpsink.c1361
-rw-r--r--utils/audio/gstavdtpsink.h101
-rw-r--r--utils/audio/gstbluetooth.c104
-rw-r--r--utils/audio/gstrtpsbcpay.c351
-rw-r--r--utils/audio/gstrtpsbcpay.h66
-rw-r--r--utils/audio/gstsbcdec.c223
-rw-r--r--utils/audio/gstsbcdec.h67
-rw-r--r--utils/audio/gstsbcenc.c602
-rw-r--r--utils/audio/gstsbcenc.h75
-rw-r--r--utils/audio/gstsbcparse.c222
-rw-r--r--utils/audio/gstsbcparse.h69
-rw-r--r--utils/audio/gstsbcutil.c521
-rw-r--r--utils/audio/gstsbcutil.h77
-rw-r--r--utils/audio/headset.c1924
-rw-r--r--utils/audio/headset.h77
-rw-r--r--utils/audio/ipc.c119
-rw-r--r--utils/audio/ipc.h308
-rw-r--r--utils/audio/main.c170
-rw-r--r--utils/audio/manager.c1571
-rw-r--r--utils/audio/manager.h50
-rw-r--r--utils/audio/pcm_bluetooth.c1665
-rw-r--r--utils/audio/rtp.h76
-rw-r--r--utils/audio/sink.c563
-rw-r--r--utils/audio/sink.h32
-rwxr-xr-xutils/audio/test-audio27
-rw-r--r--utils/audio/unix.c1155
-rw-r--r--utils/audio/unix.h26
-rw-r--r--utils/common/Makefile.am16
-rw-r--r--utils/common/Makefile.in485
-rw-r--r--utils/common/error.c126
-rw-r--r--utils/common/error.h49
-rw-r--r--utils/common/glib-helper.c1283
-rw-r--r--utils/common/glib-helper.h96
-rw-r--r--utils/common/logging.c106
-rw-r--r--utils/common/logging.h38
-rw-r--r--utils/common/oui.c109
-rw-r--r--utils/common/oui.h25
-rw-r--r--utils/common/ppoll.h16
-rw-r--r--utils/common/sdp-glib.c239
-rw-r--r--utils/common/sdp-xml.c793
-rw-r--r--utils/common/sdp-xml.h61
-rw-r--r--utils/common/test_textfile.c187
-rw-r--r--utils/common/textfile.c463
-rw-r--r--utils/common/textfile.h42
-rw-r--r--utils/common/uinput.h586
-rwxr-xr-xutils/config.guess1516
-rw-r--r--utils/config.h.in83
-rwxr-xr-xutils/config.sub1626
-rwxr-xr-xutils/configure13503
-rw-r--r--utils/configure.in61
-rw-r--r--utils/cups/Makefile.am17
-rw-r--r--utils/cups/Makefile.in493
-rw-r--r--utils/cups/cups.h32
-rw-r--r--utils/cups/hcrp.c350
-rw-r--r--utils/cups/main.c711
-rw-r--r--utils/cups/sdp.c117
-rw-r--r--utils/cups/spp.c116
-rwxr-xr-xutils/depcomp589
-rw-r--r--utils/doc/Makefile.am5
-rw-r--r--utils/doc/Makefile.in348
-rw-r--r--utils/doc/adapter-api.txt284
-rw-r--r--utils/doc/agent-api.txt91
-rw-r--r--utils/doc/audio-api.txt136
-rw-r--r--utils/doc/device-api.txt133
-rw-r--r--utils/doc/input-api.txt36
-rw-r--r--utils/doc/manager-api.txt56
-rw-r--r--utils/doc/network-api.txt38
-rw-r--r--utils/doc/serial-api.txt37
-rw-r--r--utils/dund/Makefile.am20
-rw-r--r--utils/dund/Makefile.in540
-rw-r--r--utils/dund/dun.c331
-rw-r--r--utils/dund/dund.172
-rw-r--r--utils/dund/dund.h51
-rw-r--r--utils/dund/lib.h88
-rw-r--r--utils/dund/main.c635
-rw-r--r--utils/dund/msdun.c151
-rw-r--r--utils/dund/sdp.c208
-rw-r--r--utils/eglib/Makefile.am8
-rw-r--r--utils/eglib/Makefile.in459
-rw-r--r--utils/eglib/glib.h1
-rw-r--r--utils/eglib/gmain.c1976
-rw-r--r--utils/eglib/gmain.h404
-rw-r--r--utils/eglib/gmodule.c88
-rw-r--r--utils/eglib/gmodule.h21
-rw-r--r--utils/gdbus/Makefile.am8
-rw-r--r--utils/gdbus/Makefile.in458
-rw-r--r--utils/gdbus/gdbus.h126
-rw-r--r--utils/gdbus/mainloop.c299
-rw-r--r--utils/gdbus/object.c660
-rw-r--r--utils/gdbus/watch.c346
-rw-r--r--utils/hcid/Makefile.am64
-rw-r--r--utils/hcid/Makefile.in755
-rw-r--r--utils/hcid/adapter.c4577
-rw-r--r--utils/hcid/adapter.h165
-rw-r--r--utils/hcid/agent.c730
-rw-r--r--utils/hcid/agent.h71
-rw-r--r--utils/hcid/bluetooth.conf37
-rw-r--r--utils/hcid/dbus-api.txt1401
-rw-r--r--utils/hcid/dbus-common.c364
-rw-r--r--utils/hcid/dbus-common.h47
-rw-r--r--utils/hcid/dbus-database.c380
-rw-r--r--utils/hcid/dbus-database.h35
-rw-r--r--utils/hcid/dbus-error.c91
-rw-r--r--utils/hcid/dbus-error.h33
-rw-r--r--utils/hcid/dbus-hci.c2713
-rw-r--r--utils/hcid/dbus-hci.h80
-rw-r--r--utils/hcid/dbus-sdp.c1125
-rw-r--r--utils/hcid/dbus-sdp.h42
-rw-r--r--utils/hcid/dbus-security.c1112
-rw-r--r--utils/hcid/dbus-security.h50
-rw-r--r--utils/hcid/dbus-service.c746
-rw-r--r--utils/hcid/dbus-service.h47
-rw-r--r--utils/hcid/device.c1601
-rw-r--r--utils/hcid/device.h70
-rw-r--r--utils/hcid/hcid.8101
-rw-r--r--utils/hcid/hcid.conf57
-rw-r--r--utils/hcid/hcid.conf.5227
-rw-r--r--utils/hcid/hcid.h218
-rw-r--r--utils/hcid/kword.c102
-rw-r--r--utils/hcid/kword.h37
-rw-r--r--utils/hcid/lexer.c1946
-rw-r--r--utils/hcid/lexer.l160
-rwxr-xr-xutils/hcid/list-devices52
-rw-r--r--utils/hcid/main.c971
-rw-r--r--utils/hcid/manager.c683
-rw-r--r--utils/hcid/manager.h36
-rw-r--r--utils/hcid/parser.c2084
-rw-r--r--utils/hcid/parser.h121
-rw-r--r--utils/hcid/parser.y360
-rw-r--r--utils/hcid/plugin.c185
-rw-r--r--utils/hcid/plugin.h33
-rw-r--r--utils/hcid/security.c1037
-rw-r--r--utils/hcid/server.c68
-rw-r--r--utils/hcid/server.h31
-rw-r--r--utils/hcid/service-did.xml33
-rw-r--r--utils/hcid/service-ftp.xml37
-rw-r--r--utils/hcid/service-opp.xml50
-rw-r--r--utils/hcid/service-record.dtd66
-rw-r--r--utils/hcid/service-spp.xml25
-rwxr-xr-xutils/hcid/simple-agent112
-rwxr-xr-xutils/hcid/simple-service127
-rw-r--r--utils/hcid/storage.c707
-rw-r--r--utils/hcid/telephony.c44
-rw-r--r--utils/hcid/telephony.h26
-rwxr-xr-xutils/hcid/test-adapter90
-rwxr-xr-xutils/hcid/test-device124
-rwxr-xr-xutils/hcid/test-discovery43
-rwxr-xr-xutils/hcid/test-manager27
-rw-r--r--utils/hidd/Makefile.am22
-rw-r--r--utils/hidd/Makefile.in540
-rw-r--r--utils/hidd/fakehid.c669
-rw-r--r--utils/hidd/fakehid.txt134
-rw-r--r--utils/hidd/hidd.141
-rw-r--r--utils/hidd/hidd.h34
-rw-r--r--utils/hidd/main.c860
-rw-r--r--utils/hidd/sdp.c352
-rw-r--r--utils/input/Makefile.am24
-rw-r--r--utils/input/Makefile.in508
-rw-r--r--utils/input/device.c1171
-rw-r--r--utils/input/device.h50
-rw-r--r--utils/input/fakehid.c412
-rw-r--r--utils/input/fakehid.h39
-rw-r--r--utils/input/input-api.txt103
-rw-r--r--utils/input/input.conf9
-rw-r--r--utils/input/main.c154
-rw-r--r--utils/input/manager.c801
-rw-r--r--utils/input/manager.h28
-rw-r--r--utils/input/server.c153
-rw-r--r--utils/input/server.h25
-rw-r--r--utils/input/storage.c364
-rw-r--r--utils/input/storage.h41
-rwxr-xr-xutils/input/test-input45
-rwxr-xr-xutils/install-sh519
-rw-r--r--utils/ltmain.sh6930
-rwxr-xr-xutils/missing367
-rw-r--r--utils/network/Makefile.am24
-rw-r--r--utils/network/Makefile.in509
-rw-r--r--utils/network/bridge.c148
-rw-r--r--utils/network/bridge.h30
-rw-r--r--utils/network/common.c396
-rw-r--r--utils/network/common.h42
-rw-r--r--utils/network/connection.c719
-rw-r--r--utils/network/connection.h34
-rw-r--r--utils/network/main.c256
-rw-r--r--utils/network/manager.c855
-rw-r--r--utils/network/manager.h43
-rw-r--r--utils/network/network-api.txt199
-rw-r--r--utils/network/network.conf37
-rw-r--r--utils/network/server.c1097
-rw-r--r--utils/network/server.h33
-rwxr-xr-xutils/network/test-network37
-rw-r--r--utils/pand/Makefile.am22
-rw-r--r--utils/pand/Makefile.in540
-rw-r--r--utils/pand/bnep.c311
-rw-r--r--utils/pand/main.c798
-rw-r--r--utils/pand/pand.177
-rw-r--r--utils/pand/pand.h42
-rw-r--r--utils/pand/sdp.c247
-rw-r--r--utils/plugins/Makefile.am43
-rw-r--r--utils/plugins/Makefile.in536
-rw-r--r--utils/plugins/echo.c162
-rw-r--r--utils/plugins/netlink.c126
-rw-r--r--utils/plugins/storage.c42
-rw-r--r--utils/rfcomm/Makefile.am34
-rw-r--r--utils/rfcomm/Makefile.in603
-rw-r--r--utils/rfcomm/kword.c65
-rw-r--r--utils/rfcomm/kword.h46
-rw-r--r--utils/rfcomm/lexer.c1828
-rw-r--r--utils/rfcomm/lexer.l114
-rw-r--r--utils/rfcomm/main.c845
-rw-r--r--utils/rfcomm/parser.c1736
-rw-r--r--utils/rfcomm/parser.h88
-rw-r--r--utils/rfcomm/parser.y172
-rw-r--r--utils/rfcomm/rfcomm.1137
-rw-r--r--utils/rfcomm/rfcomm.conf17
-rw-r--r--utils/sbc/Makefile.am28
-rw-r--r--utils/sbc/Makefile.in516
-rw-r--r--utils/sbc/sbc.c1411
-rw-r--r--utils/sbc/sbc.h97
-rw-r--r--utils/sbc/sbc_math.h72
-rw-r--r--utils/sbc/sbc_tables.h167
-rw-r--r--utils/sbc/sbcdec.c267
-rw-r--r--utils/sbc/sbcenc.c280
-rw-r--r--utils/sbc/sbcinfo.c319
-rw-r--r--utils/sbc/sbctester.c357
-rw-r--r--utils/scripts/Makefile.am26
-rw-r--r--utils/scripts/Makefile.in418
-rw-r--r--utils/scripts/bluetooth.default4
-rw-r--r--utils/scripts/bluetooth.init51
-rw-r--r--utils/scripts/bluetooth.rules35
-rw-r--r--utils/scripts/bluetooth_serial39
-rw-r--r--utils/sdpd/Makefile.am11
-rw-r--r--utils/sdpd/Makefile.in462
-rw-r--r--utils/sdpd/cstate.c95
-rw-r--r--utils/sdpd/request.c923
-rw-r--r--utils/sdpd/sdpd.h94
-rw-r--r--utils/sdpd/server.c280
-rw-r--r--utils/sdpd/service.c658
-rw-r--r--utils/sdpd/servicedb.c304
-rw-r--r--utils/serial/Makefile.am24
-rw-r--r--utils/serial/Makefile.in505
-rw-r--r--utils/serial/main.c150
-rw-r--r--utils/serial/manager.c1956
-rw-r--r--utils/serial/manager.h34
-rw-r--r--utils/serial/port.c404
-rw-r--r--utils/serial/port.h34
-rw-r--r--utils/serial/serial-api.txt176
-rw-r--r--utils/serial/storage.c170
-rw-r--r--utils/serial/storage.h30
-rwxr-xr-xutils/serial/test-serial40
-rw-r--r--utils/test/Makefile.am44
-rw-r--r--utils/test/Makefile.in616
-rwxr-xr-xutils/test/apitest448
-rw-r--r--utils/test/attest.c183
-rw-r--r--utils/test/auth-agent.c351
-rw-r--r--utils/test/bdaddr.868
-rw-r--r--utils/test/bdaddr.c460
-rw-r--r--utils/test/dbusdef.py59
-rw-r--r--utils/test/hciemu.c1346
-rwxr-xr-xutils/test/hsmicro20
-rwxr-xr-xutils/test/hsplay22
-rw-r--r--utils/test/hstest.c308
-rw-r--r--utils/test/l2test.c1096
-rw-r--r--utils/test/lmptest.c175
-rw-r--r--utils/test/passkey-agent.c405
-rw-r--r--utils/test/rctest.c671
-rw-r--r--utils/test/scotest.c434
-rw-r--r--utils/test/sdptest.c146
-rw-r--r--utils/tools/Makefile.am103
-rw-r--r--utils/tools/Makefile.in791
-rw-r--r--utils/tools/avctrl.839
-rw-r--r--utils/tools/avctrl.c248
-rw-r--r--utils/tools/avinfo.c660
-rw-r--r--utils/tools/bccmd.8130
-rw-r--r--utils/tools/bccmd.c1218
-rw-r--r--utils/tools/ciptool.168
-rw-r--r--utils/tools/ciptool.c498
-rw-r--r--utils/tools/csr.c2852
-rw-r--r--utils/tools/csr.h552
-rw-r--r--utils/tools/csr_3wire.c60
-rw-r--r--utils/tools/csr_bcsp.c255
-rw-r--r--utils/tools/csr_h4.c165
-rw-r--r--utils/tools/csr_hci.c160
-rw-r--r--utils/tools/csr_usb.c180
-rw-r--r--utils/tools/dfu.c168
-rw-r--r--utils/tools/dfu.h107
-rw-r--r--utils/tools/dfubabel.138
-rw-r--r--utils/tools/dfubabel.c211
-rw-r--r--utils/tools/dfutool.153
-rw-r--r--utils/tools/dfutool.c788
-rw-r--r--utils/tools/example.psr12
-rw-r--r--utils/tools/hciattach.8122
-rw-r--r--utils/tools/hciattach.c1392
-rw-r--r--utils/tools/hciattach_st.c276
-rw-r--r--utils/tools/hciconfig.8276
-rw-r--r--utils/tools/hciconfig.c1749
-rw-r--r--utils/tools/hcisecfilter.c155
-rw-r--r--utils/tools/hcitool.1206
-rw-r--r--utils/tools/hcitool.c2435
-rw-r--r--utils/tools/hid2hci.845
-rw-r--r--utils/tools/hid2hci.c390
-rw-r--r--utils/tools/l2ping.167
-rw-r--r--utils/tools/l2ping.c290
-rw-r--r--utils/tools/ppporc.c273
-rw-r--r--utils/tools/sdptool.1130
-rw-r--r--utils/tools/sdptool.c4055
-rw-r--r--utils/tools/ubcsp.c1193
-rw-r--r--utils/tools/ubcsp.h208
-rwxr-xr-xutils/ylwrap223
338 files changed, 156905 insertions, 0 deletions
diff --git a/utils/AUTHORS b/utils/AUTHORS
new file mode 100644
index 00000000..7f88d7f0
--- /dev/null
+++ b/utils/AUTHORS
@@ -0,0 +1,31 @@
+Maxim Krasnyansky <maxk@qualcomm.com>
+Marcel Holtmann <marcel@holtmann.org>
+Stephen Crane <steve.crane@rococosoft.com>
+Jean Tourrilhes <jt@hpl.hp.com>
+Jan Beutel <j.beutel@ieee.org>
+Ilguiz Latypov <ilatypov@superbt.com>
+Thomas Moser <thomas.moser@tmoser.ch>
+Nils Faerber <nils@kernelconcepts.de>
+Martin Leopold <martin@leopold.dk>
+Wolfgang Heidrich <wolfgang.heidrich@esk.fhg.de>
+Fabrizio Gennari <fabrizio.gennari@philips.com>
+Brad Midgley <bmidgley@xmission.com>
+Henryk Ploetz <henryk@ploetzli.ch>
+Philip Blundell <pb@nexus.co.uk>
+Johan Hedberg <johan.hedberg@nokia.com>
+Claudio Takahasi <claudio.takahasi@indt.org.br>
+Eduardo Rocha <eduardo.rocha@indt.org.br>
+Denis Kenzior <denis.kenzior@trolltech.com>
+Frederic Dalleau <frederic.dalleau@access-company.com>
+Frederic Danis <frederic.danis@access-company.com>
+Luiz Augusto von Dentz <luiz.dentz@gmail.com>
+Fabien Chevalier <fabchevalier@free.fr>
+Ohad Ben-Cohen <ohad@bencohen.org>
+Daniel Gollub <dgollub@suse.de>
+Tom Patzig <tpatzig@suse.de>
+Kai Vehmanen <kai.vehmanen@nokia.com>
+Vinicius Gomes <vinicius.gomes@openbossa.org>
+Alok Barsode <alok.barsode@azingo.com>
+Bastien Nocera <hadess@hadess.net>
+Albert Huang <albert@csail.mit.edu>
+Glenn Durfee <gdurfee@google.com>
diff --git a/utils/COPYING b/utils/COPYING
new file mode 100644
index 00000000..3912109b
--- /dev/null
+++ b/utils/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/utils/COPYING.LIB b/utils/COPYING.LIB
new file mode 100644
index 00000000..8add30ad
--- /dev/null
+++ b/utils/COPYING.LIB
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/utils/ChangeLog b/utils/ChangeLog
new file mode 100644
index 00000000..bdc21e73
--- /dev/null
+++ b/utils/ChangeLog
@@ -0,0 +1,803 @@
+ver 3.35:
+ Add UUID-128 support for service discovery.
+ Fix usage of friendly names for service discovery.
+ Fix authorization when experiemental is disabled.
+ Fix uninitialized variable in passkey request handling.
+ Enable output of timestamps for l2test and rctest.
+
+ Note:
+ This version needs at least bluez-libs-3.35
+
+ver 3.34:
+ Use safe function versions for SDP client handling.
+ Fix issue with RemoveDevice during discovery procedure.
+ Fix collect for non-persistent service records.
+
+ Note:
+ This version needs at least bluez-libs-3.34
+
+ver 3.33:
+ Add support for handling Simple Pairing.
+ Add Simple Pairing support to Agent interface.
+ Add ReleaseMode method to Adapter interface.
+ Add DiscoverServices method to Device interface.
+ Remove obsolete code and cleanup the repository.
+ Move over to use the libgdbus API.
+
+ Note:
+ This version needs at least bluez-libs-3.33
+
+ver 3.32:
+ Add support for switching HID proxy devices from Dell.
+ Add more Bluetooth client/server helper functions.
+ Add support for input service idle timeout option.
+ Fix BNEP reconnection handling.
+ Fix return value for snd_pcm_hw_params() calls.
+ Use upper-case addresses for object paths.
+ Remove HAL support helpers.
+ Remove inotify support.
+ Remove service daemon activation handling.
+ Remove uneeded D-Bus API extension.
+
+ Note:
+ This version needs at least bluez-libs-3.32
+
+ver 3.31:
+ Create device object for all pairing cases.
+ Convert authorization to internal function calls.
+ Add initial support for Headset Audio Gateway role.
+ Add generic Bluetooth helper functions for GLib.
+ Fix endiannes handling of connection handles.
+ Don't optimize when debug is enabled.
+
+ Note:
+ This version needs at least bluez-libs-3.31
+
+ver 3.30:
+ Convert audio service into a plugin.
+ Convert input service into a plugin.
+ Convert serial service into a plugin.
+ Convert network service into a plugin.
+ Emit old device signals when a property is changed.
+ Fix missing DiscoverDevices and CancelDiscovery methods.
+ Add basic support for Bluetooth sessions.
+ Add avinfo utility for AVDTP/A2DP classification.
+ Remove build option for deprecated sdpd binary.
+
+ Note:
+ This version needs at least bluez-libs-3.30
+
+ver 3.29:
+ Introduce new D-Bus based API.
+ Add more SBC optimizations.
+ Add support for PS3 remote devices.
+ Fix alignment trap in SDP server.
+
+ Note:
+ This version needs at least bluez-libs-3.29
+
+ver 3.28:
+ Add support for role switch for audio service.
+ Add disconnect timer for audio service.
+ Add disconnect detection to ALSA plugin.
+ Add more SBC optimizations.
+ Fix alignment issue of SDP server.
+ Remove support for SDP parsing via expat.
+
+ Note:
+ This version needs at least bluez-libs-3.28
+
+ver 3.27:
+ Update uinput.h with extra key definitions.
+ Add support for input connect/disconnect callbacks.
+ Add ifdefs around some baud rate definitions.
+ Add proper HFP service level connection handling.
+ Add basic headset automatic disconnect support.
+ Add support for new SBC API.
+ Fix SBC decoder noise at high bitpools.
+ Use 32-bit multipliers for further SBC optimization.
+ Check for RFCOMM connection state in SCO connect callback.
+ Make use of parameters selected in ALSA plugin.
+
+ Note:
+ This version needs at least bluez-libs-3.27
+
+ver 3.26:
+ Fix compilation issues with UCHAR_MAX, USHRT_MAX and UINT_MAX.
+ Improve handling of different audio transports.
+ Enable services by default and keep old daemons disabled.
+
+ Note:
+ This version needs at least bluez-libs-3.26
+
+ver 3.25:
+ Add limited support for Handsfree profile.
+ Add limited support for MPEG12/MP3 codec.
+ Add basic support for UNITINFO and SUBUNITINFO.
+ Add more SBC optimizations.
+ Fix external service (un)registration.
+ Allow GetInfo and GetAddress to fail.
+
+ Note:
+ This version needs at least bluez-libs-3.25
+
+ver 3.24:
+ Add TCP connection support for serial proxy.
+ Add fix for Logitech HID proxy switching.
+ Add missing macros, MIN, MAX, ABS and CLAMP.
+ Add more SBC encoder optimizations.
+ Add initial mechanism to handle headset commands.
+ Fix connecting to handsfree profile headsets.
+ Use proper function for checking signal name.
+
+ Note:
+ This version needs at least bluez-libs-3.24
+
+ver 3.23:
+ Fix key search function to honor the mmap area size.
+ Fix Avahi integration of network service.
+ Add new plugin communication for audio service.
+ Enable basic AVRCP support by default.
+ More optimizations to the SBC library.
+ Create common error definitions.
+
+ Note:
+ This version needs at least bluez-libs-3.23
+
+ver 3.22:
+ Add missing include file from audio service.
+ Add SBC conformance test utility.
+ Add basic uinput support for AVRCP.
+ Fix L2CAP socket leak in audio service.
+ Fix buffer usage in GStreamer plugin.
+
+ Note:
+ This version needs at least bluez-libs-3.22
+
+ver 3.21:
+ Add initial AVRCP support.
+ Add A2DP sink support to GStreamer plugin.
+ Fix interoperability with A2DP suspend.
+ Fix sign error in 8-subband encoder.
+ Fix handling of service classes length size.
+ Store Extended Inquiry Response data information.
+ Publish device id information through EIR.
+ Support higher baud rates for Ericcson based chips.
+
+ Note:
+ This version needs at least bluez-libs-3.21
+
+ver 3.20:
+ Fix GStreamer plugin file type detection.
+ Fix potential infinite loop in inotify support.
+ Fix D-Bus signatures for dict handling.
+ Fix issues with service activation.
+ Fix SDP failure handling of audio service.
+ Fix various memory leaks in input service.
+ Add secure device creation method to input service.
+ Add service information methods to serial service.
+ Add config file support to network service.
+ Add scripting capability to network service.
+ Add special on-mode handling.
+ Add optimization for SBC encoder.
+ Add tweaks for D-Bus 1.1.x libraries.
+ Add support for inquiry transmit power level.
+
+ Note:
+ This version needs at least bluez-libs-3.20
+
+ver 3.19:
+ Limit range of bitpool announced while in ACP side.
+ Use poll instead of usleep to wait for worker thread.
+ Use default event mask from the specification.
+ Add HID proxy support for Logitech diNovo Edge dongle.
+ Add refresh option to re-request device names.
+ Show correct connection link type.
+
+ Note:
+ This version needs at least bluez-libs-3.19
+
+ver 3.18:
+ Implement proper locking for headsets.
+ Fix various A2DP SEP locking issues.
+ Fix and cleanup audio stream handling.
+ Fix stream starting if suspend request is pending.
+ Fix A2DP and AVDTP endianess problems.
+ Add network timeout and retransmission support.
+ Add more detailed decoding of EIR elements.
+
+ Note:
+ This version needs at least bluez-libs-3.18
+
+ver 3.17:
+ Fix crashes in audio and network services.
+ Check PAN source and destination roles.
+ Only export the needed symbols for the plugins.
+
+ Note:
+ This version needs at least bluez-libs-3.17
+
+ver 3.16:
+ Add support for headsets with SCO audio over HCI.
+ Add support for auto-create through ALSA plugin.
+ Add support for ALSA plugin parameters.
+ Add GStreamer plugin with SBC decoder and encoder.
+ Fix network service NAP, GN and PANU servers.
+ Set EIR information from SDP database.
+
+ Note:
+ This version needs at least bluez-libs-3.16
+
+ver 3.15:
+ Add A2DP support to the audio service.
+ Add proxy support to the serial service.
+ Set service classes value from SDP database.
+
+ Note:
+ This version needs at least bluez-libs-3.15
+
+ver 3.14:
+ Add missing signals for the adapter interface.
+ Add basic commands for Simple Pairing.
+ Add correct Simple Pairing and EIR interaction.
+ Add missing properties for remote information.
+ Add EPoX endian quirk to the input service.
+ Fix HID descriptor import and storage functions.
+ Fix handling of adapters in raw mode.
+ Fix remote device listing methods.
+
+ Note:
+ This version needs at least bluez-libs-3.14
+
+ver 3.13:
+ Fix some issues with the headset support.
+ Fix concurrent pending connection attempts.
+ Fix usage of devname instead of netdev.
+ Add identifier for Nokia SyncML records.
+ Add command for reading the CSR chip revision.
+ Add generic CSR radio test support.
+
+ Note:
+ This version needs at least bluez-libs-3.13
+
+ver 3.12:
+ Add support for limited discovery mode.
+ Add support for setting of event mask.
+ Add GetRemoteServiceIdentifiers method.
+ Add skeleton for local D-Bus server.
+ Add headset gain control methods.
+ Fix various headset implementation issues.
+ Fix various serial port service issues.
+ Fix various input service issues.
+ Let CUPS plugin discover printers in range.
+ Improve the BCM2035 UART init routine.
+ Ignore connection events for non-ACL links.
+
+ Note:
+ This version needs at least bluez-libs-3.12
+
+ver 3.11:
+ Update API documentation.
+ Minimize SDP root records and browse groups.
+ Use same decoder for text and URL strings.
+ Fix SDP pattern extraction for XML.
+ Fix network connection persistent state.
+ Add network connection helper methods.
+ Add initial version of serial port support.
+ Add class of device tracking.
+
+ Note:
+ This version needs at least bluez-libs-3.11
+
+ver 3.10.1:
+ Add option to disable installation of manual pages.
+ Fix input service encryption setup.
+ Fix serial service methods.
+ Fix network service connection handling.
+ Provide a simple init script.
+
+ver 3.10:
+ Add initial version of network service.
+ Add initial version of serial service.
+ Add initial version of input service.
+ Add initial version of audio service.
+ Add authorization framework.
+ Add integer based SBC library.
+
+ Note:
+ This version needs at least bluez-libs-3.10
+
+ver 3.9:
+ Add RemoteDeviceDisconnectRequested signal.
+ Add updated service framework.
+ Add embedded GLib library.
+ Add support for using system GLib library.
+ Create internal SDP server library.
+
+ Note:
+ This version needs at least bluez-libs-3.9
+
+ver 3.8:
+ Sort discovered devices list based on their RSSI.
+ Send DiscoverableTimeoutChanged signal.
+ Fix local and remote name validity checking.
+ Add ListRemoteDevices and ListRecentRemoteDevices methods.
+ Add basic integration of confirmation concept.
+ Add support for service record description via XML.
+ Add support for external commands to the RFCOMM utility.
+ Add experimental service and authorization API.
+
+ Note:
+ This version needs at least bluez-libs-3.8
+
+ver 3.7:
+ Fix class of device handling.
+ Fix error replies with pairing and security mode 3.
+ Fix disconnect method for RFCOMM connections.
+ Add match pattern for service searches.
+ Add support for prioritized watches.
+
+ Note:
+ This version needs at least bluez-libs-3.7
+
+ver 3.6.1:
+ Fix IO channel race conditions.
+ Fix pairing issues on big endian systems.
+ Fix pairing issues with page timeout errors.
+ Fix pairing state for security mode 3 requests.
+ Switch to user as default security manager mode.
+
+ver 3.6:
+ Update D-Bus based RFCOMM interface support.
+ Use L2CAP raw sockets for HCI connection creation.
+ Add periodic discovery support to the D-Bus interface.
+ Add initial support for device names via EIR.
+ Add proper UTF-8 validation of device names.
+ Add support for the J-Three keyboard.
+
+ Note:
+ This version needs at least bluez-libs-3.6
+
+ver 3.5:
+ Fix and cleanup watch functionality.
+ Add support for periodic inquiry mode.
+ Add support for asynchronous SDP requests.
+ Add more request owner tracking.
+ Document pageto and discovto options.
+
+ Note:
+ This version needs at least bluez-libs-3.5
+
+ver 3.4:
+ Improve error reporting for failed HCI commands.
+ Improve handling of CancelBonding.
+ Fixed bonding reply message when disconnected.
+
+ Note:
+ This version needs at least bluez-libs-3.4
+
+ver 3.3:
+ Don't change inquiry mode for Bluetooth 1.1 adapters.
+ Add udev rules for Bluetooth serial PCMCIA cards.
+ Add Cancel and Release methods for passkey agents.
+ Add GetRemoteClass method.
+ Convert to using ppoll() and pselect().
+ Initialize allocated memory to zero.
+ Remove bcm203x firmware loader.
+
+ Note:
+ This version needs at least bluez-libs-3.3
+
+ver 3.2:
+ Only check for the low-level D-Bus library.
+ Update possible device minor classes.
+ Fix timeout for pending reply.
+ Add more Inquiry with RSSI quirks.
+ Sleep only 100 msecs for device detection.
+ Don't send BondingCreated on link key renewal.
+ Allow storing of all UTF-8 remote device names.
+ Create storage filenames with a generic function.
+
+ Note:
+ This version needs at least bluez-libs-3.2
+
+ver 3.1:
+ Fix handling of raw mode devices.
+ Fix busy loop in UUID extraction routine.
+ Remove inquiry mode setting.
+ Remove auth and encrypt settings.
+
+ Note:
+ This version needs at least bluez-libs-3.1
+
+ver 3.0:
+ Implement the new BlueZ D-Bus API.
+
+ Note:
+ This version needs at least bluez-libs-3.0
+
+ver 2.25:
+ Use %jx instead of %llx for uint64_t and int64_t.
+ Allow null-terminated text strings.
+ Add UUID for N-Gage games.
+ Add UUID for Apple Macintosh Attributes.
+ Add Apple attributes and iSync records.
+ Add definitions for Apple Agent.
+ Add support for the Handsfree Audio Gateway service.
+ Add support for choosing a specific record handle.
+ Add support for dialup/telephone connections.
+
+ Note:
+ This version needs at least bluez-libs-2.25
+
+ver 2.24:
+ Fix display of SDP text and data strings.
+ Add support for device scan property.
+ Update the D-Bus policy configuration file.
+
+ Note:
+ This version needs at least bluez-libs-2.24
+
+ver 2.23:
+ Update the new D-Bus interface.
+ Make dfutool ready for big endian architectures.
+ Add support for AVRCP specific service records.
+ Add support for writing complex BCCMD commands.
+ Add the new BCCMD interface utility.
+ Add MicroBCSP implementation from CSR.
+ Add HCI emulation tool.
+ Add fake HID support for old EPoX presenters.
+ Reject connections from unknown HID devices.
+
+ Note:
+ This version needs at least bluez-libs-2.23
+
+ver 2.22:
+ Remove D-Bus 0.23 support.
+ Add initial version of the new D-Bus interface.
+ Add support for extended inquiry response commands.
+ Add support for the Logitech diNovo Media Desktop Laser.
+ Add compile time buffer checks (FORTIFY SOURCE).
+
+ Note:
+ This version needs at least bluez-libs-2.22
+
+ver 2.21:
+ Move create_dirs() and create_file() into the textfile library.
+ Let textfile_put() also replace the last key value pair.
+ Fix memory leaks with textfile_get() usage.
+ Fix infinite loops and false positive matches.
+ Don't retrieve stored link keys for RAW devices.
+ Document the putkey and delkey commands.
+ Show supported commands also in clear text.
+ Support volatile changes of the BD_ADDR for CSR chips.
+
+ Note:
+ This version needs at least bluez-libs-2.21
+
+ver 2.20:
+ Add support for extended inquiry response.
+ Add support for HotSync service record.
+ Add support for ActiveSync service record.
+ Add ActiveSync networking support.
+ Fix D-Bus crashes with new API versions.
+
+ Note:
+ This version needs at least bluez-libs-2.20
+
+ver 2.19:
+ Fix the GCC 4.0 warnings.
+ Fix off by one memory allocation error.
+ Fix security problem with escape characters in device name.
+ Send D-Bus signals for inquiry results and remote name resolves.
+ Add support for device specific SDP records.
+
+ Note:
+ This version needs at least bluez-libs-2.19
+
+ver 2.18:
+ Support D-Bus 0.23 and 0.33 API versions.
+ Support reading of complex BCCMD values.
+ Support minimum and maximum encryption key length.
+ Add support for inquiry scan type.
+ Add tool for the CSR BCCMD interface.
+ Add first draft of the Audio/Video control utility.
+ Add disconnect timer support for the A2DP ALSA plugin.
+ Make SBC parameters configurable.
+ Replace non-printable characters in device names.
+
+ Note:
+ This version needs at least bluez-libs-2.18
+
+ver 2.17:
+ Set the storage directory through ${localstatedir}.
+ Add the textfile library for ASCII based file access.
+ Add support for return link keys event.
+ Add support for voice setting configuration.
+ Add support for page scan timeout configuration.
+ Add support for storing and deleting of stored link keys.
+ Add support for searching for services with UUID-128.
+ Add support for retrieving all possible service records.
+ Add support for a raw mode view of service records.
+ Add support for HID information caching in hidd.
+ Add support for authentication in pand and dund.
+ Add support for changing BD_ADDR of CSR chips.
+ Add pskey utility for changing CSR persistent storage values.
+ Add the firmware upgrade utility.
+ Add connection caching for the A2DP ALSA plugin.
+
+ Note:
+ This version needs at least bluez-libs-2.17
+
+ver 2.16:
+ Store link keys in ASCII based file format.
+ Support device name caching.
+ Support zero length data sizes in l2test.
+ Change default l2ping data size to 44 bytes.
+ Hide the server record and the public browse group root.
+ Read BD_ADDR if not set and if it is a raw device.
+ Add SDP language attributes.
+ Add support for browsing the L2CAP group.
+ Add support for stored pin codes for outgoing connections.
+ Add support for local commands and extended features.
+ Add support for reading CSR panic and fault codes.
+ Add config option for setting the inquiry mode.
+ Add OUI decoding support.
+ Use unlimited inquiry responses as default.
+ Use cached device names for PIN request.
+ Use the clock offset when getting the remote names.
+
+ Note:
+ This version needs at least bluez-libs-2.16
+
+ver 2.15:
+ Enable the RFCOMM service level security.
+ Add command for reading the clock offset.
+ Add command for reading the clock.
+ Don't configure raw devices.
+ Don't set inquiry scan or page scan on raw devices.
+ Don't show extended information for raw devices.
+ Support L2CAP signal sizes bigger than 2048 bytes.
+ Cleanup of the socket handling code of the test programs.
+
+ Note:
+ This version needs at least bluez-libs-2.15
+
+ver 2.14:
+ Make use of additional connection information.
+ Use library function for reading the RSSI.
+ Use library function for reading the link quality.
+ Use library function for reading the transmit power level.
+ Use library functions for the link supervision timeout.
+ Add tool for changing the device address.
+
+ Note:
+ This version needs at least bluez-libs-2.14
+
+ver 2.13:
+ Use file permission 0600 for the link key file.
+ Add support for HID attribute descriptions.
+ Add support for Device ID attributes.
+ Various whitespace cleanups.
+
+ Note:
+ This version needs at least bluez-libs-2.13
+
+ver 2.12:
+ Inherit the device specific options from the default.
+ Use --device for selecting the source device.
+ Add --nosdp option for devices with resource limitation.
+ Add support and parameter option for secure mode.
+ Add a lot of build ids and hardware revisions.
+ Update UUID translation tables.
+
+ Note:
+ This version needs at least bluez-libs-2.12
+
+ver 2.11:
+ Various cleanups to avoid inclusion of kernel headers.
+ Fix output when the CUPS backend is called without arguments.
+ Fix problems with a 64 bit userland.
+ Use Bluetooth library functions if available.
+ Use standard numbering scheme of SDP record handles.
+ Add a master option to the hidd.
+ Add support for changing the link key of a connection.
+ Add support for requesting encryption on keyboards.
+ Add support for revision information of Digianswer devices.
+ Add support for the Zoom, IBM and TDK PCMCIA cards.
+ Add checks for the OpenOBEX and the ALSA libraries.
+ Add experimental mRouter support.
+
+ Note:
+ This version needs at least bluez-libs-2.11
+
+ver 2.10:
+ Use a define for the configuration directory.
+ Fix string initialization for flags translation.
+ Check for usb_get_busses() and usb_interrupt_read().
+ Add optional support for compiling with PIE.
+ Make installation of the init scripts optional.
+ Make compiling with debug information optional.
+ Don't override CFLAGS from configure.
+
+ Note:
+ This version needs at least bluez-libs-2.10
+
+ver 2.9:
+ Retry SDP connect if busy in the CUPS backend.
+ Use packet type and allow role switch in hcitool.
+ Use the functions from the USB library for hid2hci.
+ Add Broadcom firmware loader.
+ Add EPoX endian quirk for buggy keyboards.
+ Update the autoconf/automake scripts.
+
+ Note:
+ This version needs at least bluez-libs-2.9
+
+ver 2.8:
+ Use LIBS and LDADD instead of LDFLAGS.
+ Use HIDP subclass field for HID boot protocol.
+ Set olen before calling getsockopt() in pand.
+ Restore signals for dev-up script.
+ Add PID file support for pand.
+ Add size parameter to expand_name() in hcid.
+ Add support for audio source and audio sink SDP records.
+ Add support for HID virtual cable unplug.
+ Add support for AmbiCom BT2000C card.
+
+ Note:
+ This version needs at least bluez-libs-2.8
+
+ver 2.7:
+ Add support for getting the AFH channel map.
+ Add support for AFH mode.
+ Add support for inquiry mode.
+ Add Bluetooth backend for CUPS.
+ Add the hid2hci utility.
+ Add the hidd utility.
+ Add the pand utility.
+ Add the dund utility.
+ More endian bug fixes.
+ Give udev some time to create the RFCOMM device nodes.
+ Release the TTY if no device node is found.
+ New startup script for the Bluetooth subsystem.
+ Update to the autoconf stuff.
+
+ Note:
+ This version needs at least bluez-libs-2.7
+
+ver 2.6:
+ Change default prefix to /usr.
+ Add manpages for hcid and hcid.conf.
+ Add the sdpd server daemon.
+ Add the sdptool utility.
+ Add the ciptool utility.
+
+ Note:
+ This version needs at least bluez-libs-2.6
+
+ver 2.5:
+ hcitool changes:
+ Support for requesting authentication.
+ Support for setting connection encryption.
+ Fix some endian problems.
+ hciconfig changes:
+ Show revision information for Broadcom devices.
+ Replace unprintable characters in device name.
+ hcid changes:
+ Add D-Bus support for PIN request.
+ Report an error on PIN helper failure.
+ Fix some 64-bit problems.
+ Update bluepin script for GTK2.
+
+ver 2.4:
+ hcitool changes:
+ Increase number of inquiry responses.
+ Support for transmit power level.
+ Minor updates.
+ hciconfig changes:
+ Display all 8 bytes of the features.
+ Add support for reading and writing of IAC.
+ Correct decoding class of device.
+ Use Ericsson revision command for ST Microelectronics devices.
+ Display AVM firmware version with 'revision' command.
+ New code for CSR specific revision information.
+ hciattach changes:
+ Support for ST Microelectronics specific initialization.
+ Support for 3Com card version 3.0.
+ Support for TDK, IBM and Socket cards.
+ Support for initial baud rate.
+ Update man pages.
+ Fixes for some memory leaks.
+
+ver 2.3:
+ hciconfig changes:
+ CSR firmware version is now displayed by 'revision' command.
+ Voice command is working properly on big endian machines.
+ hciattach changes:
+ Added support for Texas Bluetooth modules.
+ Added support for high UART baud rates on Ericsson modules.
+ BCSP initialization fixes.
+ Support for role switch command (hcitool).
+ RFCOMM config file parser fixes.
+ Update man pages.
+ Removed GLib dependency.
+
+ver 2.2:
+ Support for voice settings (hciconfig).
+ Minor hcitool fixes.
+ Improved configure script.
+ Added Headset testing tool.
+ Updated man pages.
+ RPM package.
+
+ver 2.1:
+ Improved BCSP initialization (hciattach).
+ Support for displaying link quality (hcitool).
+ Support for changing link supervision timeout (hcitool).
+ New RFCOMM TTY configuration tool (rfcomm).
+ Minor fixes and updates.
+
+ver 2.0:
+ BCSP initialization (hciattach).
+ Minor hciconfig fixes.
+
+ver 2.0-pr13:
+ Support for multiple pairing modes.
+ Link key database handling fixes.
+
+ver 2.0-pre12:
+ Removed max link key limit. Keys never expire.
+ Link key database is always updated. Reread PIN on SIGHUP (hcid).
+ Bluetooth script starts SDPd, if installed.
+ Other minor fixes.
+
+ver 2.0-pre11:
+ Improved link key management and more verbose logging (hcid).
+ Fixed scan command (hcitool).
+
+ver 2.0-pre10:
+ Support for reading RSSI, remote name and changing
+ connection type (hcitool).
+ Device initialization fixes (hcid).
+ Other minor fixes and improvements.
+ Build environment cleanup and fixes.
+
+ver 2.0-pre9:
+ Improved bluepin. Working X authentication.
+ Improved hcitool. New flexible cmd syntax, additional commands.
+ Human readable display of the device features.
+
+ver 2.0-pre8:
+ Additional hciconfig commands. Support for ACL and SCO MTU ioctls.
+ Support for Inventel and COM1 UART based devices.
+ Minor hcitool fixes.
+ Improved l2test. New L2CAP test modes.
+ Minor cleanup.
+
+ver 2.0-pre7:
+ Bluetooth utilities is now a separate package.
+ New build environment uses automake.
+ Moved all config files and security data to /etc/bluetooth.
+ Various cleanups.
+
+ Note:
+ Please move your /etc/hcid.conf to /etc/bluetooth
+
+ver 2.0-pre6:
+ Improved hcitool.
+ l2test minor output fixes.
+ hciattach opt to display list of supported devices.
+
+ver 2.0-pre2:
+ Additional HCI library functions.
+ Improved CSR baud rate initialization.
+ PCMCIA scripts fixes and enhancements.
+ Documentation update.
+
+ver 2.0-pre1:
+ New UART initialization utility.
+ Hot plugging support for UART based PCMCIA devices.
+ SCO testing utility.
+ New authentication utility (bluepin).
+ Minor fixes and improvements.
diff --git a/utils/INSTALL b/utils/INSTALL
new file mode 100644
index 00000000..56b077d6
--- /dev/null
+++ b/utils/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PREFIX', the package will
+use PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script). Here is a another example:
+
+ /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644
index 00000000..5c2c32fa
--- /dev/null
+++ b/utils/Makefile.am
@@ -0,0 +1,9 @@
+
+SUBDIRS = doc sbc eglib gdbus common sdpd hcid plugins \
+ network serial input audio \
+ tools rfcomm dund pand hidd \
+ cups test scripts
+
+MAINTAINERCLEANFILES = Makefile.in \
+ aclocal.m4 configure config.h.in config.sub config.guess \
+ ltmain.sh depcomp missing install-sh mkinstalldirs compile ylwrap
diff --git a/utils/Makefile.in b/utils/Makefile.in
new file mode 100644
index 00000000..ce1a4076
--- /dev/null
+++ b/utils/Makefile.in
@@ -0,0 +1,663 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(top_srcdir)/configure AUTHORS COPYING COPYING.LIB ChangeLog \
+ INSTALL NEWS config.guess config.sub depcomp install-sh \
+ ltmain.sh missing ylwrap
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = doc sbc eglib gdbus common sdpd hcid plugins \
+ network serial input audio \
+ tools rfcomm dund pand hidd \
+ cups test scripts
+
+MAINTAINERCLEANFILES = Makefile.in \
+ aclocal.m4 configure config.h.in config.sub config.guess \
+ ltmain.sh depcomp missing install-sh mkinstalldirs compile ylwrap
+
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
+ cd $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d $(distdir) || mkdir $(distdir)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-lzma: distdir
+ tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lzma*) \
+ unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-info: install-info-recursive
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-ps: install-ps-recursive
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+ install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am am--refresh check check-am clean clean-generic \
+ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
+ dist-gzip dist-lzma dist-shar dist-tarZ dist-zip distcheck \
+ distclean distclean-generic distclean-hdr distclean-libtool \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/NEWS b/utils/NEWS
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/utils/NEWS
diff --git a/utils/README b/utils/README
new file mode 100644
index 00000000..541e4eec
--- /dev/null
+++ b/utils/README
@@ -0,0 +1,40 @@
+BlueZ - Bluetooth protocol stack for Linux
+******************************************
+
+Copyright (C) 2000-2001 Qualcomm Incorporated
+Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+
+Bluetooth utilities
+
+
+Compilation and installation
+============================
+
+In order to compile Bluetooth utilities you need following software packages:
+ - Linux Bluetooth protocol stack (BlueZ)
+ - GCC compiler
+ - D-Bus library
+ - USB library
+ - Lexical Analyzer (flex, lex)
+ - YACC (yacc, bison, byacc)
+
+To configure run:
+ ./configure --prefix=/usr --mandir=/usr/share/man \
+ --sysconfdir=/etc --localstatedir=/var --libexecdir=/lib
+
+Configure automatically searches for all required components and packages.
+
+To compile and install run:
+ make && make install
+
+
+Information
+===========
+
+Mailing lists:
+ bluez-users@lists.sf.net - BlueZ general questions and discussions
+ bluez-devel@lists.sf.net - BlueZ development
+
+For additional information about the project visit BlueZ web site:
+ http://www.bluez.org
diff --git a/utils/acinclude.m4 b/utils/acinclude.m4
new file mode 100644
index 00000000..d99b459f
--- /dev/null
+++ b/utils/acinclude.m4
@@ -0,0 +1,334 @@
+AC_DEFUN([AC_PROG_CC_PIE], [
+ AC_CACHE_CHECK([whether ${CC-cc} accepts -fPIE], ac_cv_prog_cc_pie, [
+ echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_pie=yes
+ else
+ ac_cv_prog_cc_pie=no
+ fi
+ rm -rf conftest*
+ ])
+])
+
+AC_DEFUN([AC_FUNC_PPOLL], [
+ AC_CHECK_FUNC(ppoll, dummy=yes, AC_DEFINE(NEED_PPOLL, 1,
+ [Define to 1 if you need the ppoll() function.]))
+])
+
+AC_DEFUN([AC_INIT_BLUEZ], [
+ AC_PREFIX_DEFAULT(/usr/local)
+
+ if (test "${CFLAGS}" = ""); then
+ CFLAGS="-Wall -O2"
+ fi
+
+ if (test "${prefix}" = "NONE"); then
+ dnl no prefix and no sysconfdir, so default to /etc
+ if (test "$sysconfdir" = '${prefix}/etc'); then
+ AC_SUBST([sysconfdir], ['/etc'])
+ fi
+
+ dnl no prefix and no localstatedir, so default to /var
+ if (test "$localstatedir" = '${prefix}/var'); then
+ AC_SUBST([localstatedir], ['/var'])
+ fi
+
+ dnl no prefix and no libexecdir, so default to /lib
+ if (test "$libexecdir" = '${exec_prefix}/libexec'); then
+ AC_SUBST([libexecdir], ['/lib'])
+ fi
+
+ dnl no prefix and no mandir, so use ${prefix}/share/man as default
+ if (test "$mandir" = '${prefix}/man'); then
+ AC_SUBST([mandir], ['${prefix}/share/man'])
+ fi
+
+ prefix="${ac_default_prefix}"
+ fi
+
+ if (test "${libdir}" = '${exec_prefix}/lib'); then
+ libdir="${prefix}/lib"
+ fi
+
+ if (test "$sysconfdir" = '${prefix}/etc'); then
+ configdir="${prefix}/etc/bluetooth"
+ else
+ configdir="${sysconfdir}/bluetooth"
+ fi
+
+ if (test "$localstatedir" = '${prefix}/var'); then
+ storagedir="${prefix}/var/lib/bluetooth"
+ else
+ storagedir="${localstatedir}/lib/bluetooth"
+ fi
+
+ servicedir="${libdir}/bluetooth"
+
+ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
+ [Directory for the configuration files])
+ AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
+ [Directory for the storage files])
+ AC_DEFINE_UNQUOTED(SERVICEDIR, "${servicedir}",
+ [Directory for the service programs])
+])
+
+AC_DEFUN([AC_PATH_BLUEZ], [
+ PKG_CHECK_MODULES(BLUEZ, bluez, dummy=yes,
+ AC_MSG_ERROR(Bluetooth library is required))
+ AC_SUBST(BLUEZ_CFLAGS)
+ AC_SUBST(BLUEZ_LIBS)
+])
+
+AC_DEFUN([AC_PATH_DBUS], [
+ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.0, dummy=yes,
+ AC_MSG_ERROR(D-Bus library is required))
+ AC_CHECK_LIB(dbus-1, dbus_watch_get_unix_fd, dummy=yes,
+ AC_DEFINE(NEED_DBUS_WATCH_GET_UNIX_FD, 1,
+ [Define to 1 if you need the dbus_watch_get_unix_fd() function.]))
+ AC_SUBST(DBUS_CFLAGS)
+ AC_SUBST(DBUS_LIBS)
+])
+
+AC_DEFUN([AC_PATH_GLIB], [
+ PKG_CHECK_MODULES(GLIB, glib-2.0, glib_found=yes, glib_found=no)
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+])
+
+AC_DEFUN([AC_PATH_GMODULE], [
+ PKG_CHECK_MODULES(GMODULE, gmodule-2.0, gmodule_found=yes, gmodule_found=no)
+ AC_CHECK_LIB(dl, dlopen, dummy=yes, dummy=no)
+ AC_SUBST(GMODULE_CFLAGS)
+ AC_SUBST(GMODULE_LIBS)
+])
+
+AC_DEFUN([AC_PATH_GSTREAMER], [
+ PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10 gstreamer-plugins-base-0.10, gstreamer_found=yes, gstreamer_found=no)
+ AC_SUBST(GSTREAMER_CFLAGS)
+ AC_SUBST(GSTREAMER_LIBS)
+ GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10`
+ AC_SUBST(GSTREAMER_PLUGINSDIR)
+])
+
+AC_DEFUN([AC_PATH_PULSE], [
+ PKG_CHECK_MODULES(PULSE, libpulse, pulse_found=yes, pulse_found=no)
+ AC_SUBST(PULSE_CFLAGS)
+ AC_SUBST(PULSE_LIBS)
+])
+
+AC_DEFUN([AC_PATH_ALSA], [
+ PKG_CHECK_MODULES(ALSA, alsa, alsa_found=yes, alsa_found=no)
+ AC_CHECK_LIB(rt, clock_gettime, ALSA_LIBS="$ALSA_LIBS -lrt", alsa_found=no)
+ AC_SUBST(ALSA_CFLAGS)
+ AC_SUBST(ALSA_LIBS)
+])
+
+AC_DEFUN([AC_PATH_USB], [
+ PKG_CHECK_MODULES(USB, libusb, usb_found=yes, usb_found=no)
+ AC_SUBST(USB_CFLAGS)
+ AC_SUBST(USB_LIBS)
+ AC_CHECK_LIB(usb, usb_get_busses, dummy=yes,
+ AC_DEFINE(NEED_USB_GET_BUSSES, 1,
+ [Define to 1 if you need the usb_get_busses() function.]))
+ AC_CHECK_LIB(usb, usb_interrupt_read, dummy=yes,
+ AC_DEFINE(NEED_USB_INTERRUPT_READ, 1,
+ [Define to 1 if you need the usb_interrupt_read() function.]))
+])
+
+AC_DEFUN([AC_PATH_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)
+ AC_SUBST(SNDFILE_LIBS)
+])
+
+AC_DEFUN([AC_ARG_BLUEZ], [
+ debug_enable=no
+ fortify_enable=yes
+ pie_enable=yes
+ sndfile_enable=${sndfile_found}
+ netlink_enable=no
+ usb_enable=${usb_found}
+ alsa_enable=${alsa_found}
+ glib_enable=yes
+ gstreamer_enable=${gstreamer_found}
+ audio_enable=yes
+ input_enable=yes
+ serial_enable=yes
+ network_enable=yes
+ tools_enable=yes
+ hidd_enable=no
+ pand_enable=no
+ dund_enable=no
+ cups_enable=no
+ test_enable=no
+ bccmd_enable=no
+ hid2hci_enable=no
+ dfutool_enable=no
+ manpages_enable=yes
+ configfiles_enable=yes
+ initscripts_enable=no
+ pcmciarules_enable=no
+
+ AC_ARG_ENABLE(fortify, AC_HELP_STRING([--disable-fortify], [disable compile time buffer checks]), [
+ fortify_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(pie, AC_HELP_STRING([--disable-pie], [disable position independent executables flag]), [
+ pie_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(glib, AC_HELP_STRING([--disable-glib], [disable GLib support]), [
+ glib_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(network, AC_HELP_STRING([--disable-network], [disable network plugin]), [
+ network_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [
+ serial_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(input, AC_HELP_STRING([--disable-input], [disable input plugin]), [
+ input_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(audio, AC_HELP_STRING([--disable-audio], [disable audio plugin]), [
+ audio_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(gstreamer, AC_HELP_STRING([--enable-gstreamer], [enable GStreamer support]), [
+ gstreamer_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(alsa, AC_HELP_STRING([--enable-alsa], [enable ALSA support]), [
+ alsa_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(usb, AC_HELP_STRING([--enable-usb], [enable USB support]), [
+ usb_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink], [enable NETLINK support]), [
+ netlink_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools], [install Bluetooth utilities]), [
+ tools_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(bccmd, AC_HELP_STRING([--enable-bccmd], [install BCCMD interface utility]), [
+ bccmd_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(hid2hci, AC_HELP_STRING([--enable-hid2hci], [install HID mode switching utility]), [
+ hid2hci_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(dfutool, AC_HELP_STRING([--enable-dfutool], [install DFU firmware upgrade utility]), [
+ dfutool_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(hidd, AC_HELP_STRING([--enable-hidd], [install HID daemon]), [
+ hidd_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(pand, AC_HELP_STRING([--enable-pand], [install PAN daemon]), [
+ pand_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(dund, AC_HELP_STRING([--enable-dund], [install DUN daemon]), [
+ dund_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(cups, AC_HELP_STRING([--enable-cups], [install CUPS backend support]), [
+ cups_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(test, AC_HELP_STRING([--enable-test], [install test programs]), [
+ test_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(manpages, AC_HELP_STRING([--enable-manpages], [install Bluetooth manual pages]), [
+ manpages_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(configfiles, AC_HELP_STRING([--enable-configfiles], [install Bluetooth config files]), [
+ configfiles_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(initscripts, AC_HELP_STRING([--enable-initscripts], [install Bluetooth boot scripts]), [
+ initscripts_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(pcmciarules, AC_HELP_STRING([--enable-pcmciarules], [install PCMCIA udev rules]), [
+ pcmciarules_enable=${enableval}
+ ])
+
+ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable compiling with debugging information]), [
+ debug_enable=${enableval}
+ ])
+
+ if (test "${fortify_enable}" = "yes"); then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
+ fi
+
+ if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then
+ CFLAGS="$CFLAGS -fPIE"
+ LDFLAGS="$LDFLAGS -pie"
+ fi
+
+ if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then
+ CFLAGS="$CFLAGS -g -O0"
+ fi
+
+ if (test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"); then
+ AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.])
+ fi
+
+ if (test "${glib_enable}" = "yes" && test "${glib_found}" = "yes"); then
+ AM_CONDITIONAL(GLIB, true)
+ else
+ AC_SUBST([GLIB_CFLAGS], ['-I$(top_srcdir)/eglib'])
+ AC_SUBST([GLIB_LIBS], ['$(top_builddir)/eglib/libeglib.la -ldl -rdynamic'])
+ AC_SUBST([GMODULE_CFLAGS], [''])
+ AC_SUBST([GMODULE_LIBS], [''])
+ AM_CONDITIONAL(GLIB, false)
+ fi
+
+ 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(ALSA, test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes")
+ AM_CONDITIONAL(GSTREAMER, test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes")
+ AM_CONDITIONAL(AUDIOPLUGIN, test "${audio_enable}" = "yes")
+ AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes")
+ AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
+ AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
+ AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes")
+ AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes")
+ AM_CONDITIONAL(DUND, test "${dund_enable}" = "yes")
+ AM_CONDITIONAL(CUPS, test "${cups_enable}" = "yes")
+ AM_CONDITIONAL(TEST, test "${test_enable}" = "yes")
+ AM_CONDITIONAL(TOOLS, test "${tools_enable}" = "yes")
+ AM_CONDITIONAL(BCCMD, test "${bccmd_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(CONFIGFILES, test "${configfiles_enable}" = "yes")
+ AM_CONDITIONAL(INITSCRIPTS, test "${initscripts_enable}" = "yes")
+ AM_CONDITIONAL(PCMCIARULES, test "${pcmciarules_enable}" = "yes")
+])
diff --git a/utils/aclocal.m4 b/utils/aclocal.m4
new file mode 100644
index 00000000..3ad76b3b
--- /dev/null
+++ b/utils/aclocal.m4
@@ -0,0 +1,7655 @@
+# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(AC_AUTOCONF_VERSION, [2.61],,
+[m4_warning([this file was generated for autoconf 2.61.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+
+# serial 51 AC_PROG_LIBTOOL
+
+
+# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+# -----------------------------------------------------------
+# If this macro is not defined by Autoconf, define it here.
+m4_ifdef([AC_PROVIDE_IFELSE],
+ [],
+ [m4_define([AC_PROVIDE_IFELSE],
+ [m4_ifdef([AC_PROVIDE_$1],
+ [$2], [$3])])])
+
+
+# AC_PROG_LIBTOOL
+# ---------------
+AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+ AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [AC_LIBTOOL_CXX],
+ [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+ ])])
+dnl And a similar setup for Fortran 77 support
+ AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [AC_LIBTOOL_F77],
+ [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+ AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+ [AC_LIBTOOL_GCJ],
+ [ifdef([AC_PROG_GCJ],
+ [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+ ifdef([A][M_PROG_GCJ],
+ [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+ ifdef([LT_AC_PROG_GCJ],
+ [define([LT_AC_PROG_GCJ],
+ defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+])])# AC_PROG_LIBTOOL
+
+
+# _AC_PROG_LIBTOOL
+# ----------------
+AC_DEFUN([_AC_PROG_LIBTOOL],
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Prevent multiple expansion
+define([AC_PROG_LIBTOOL], [])
+])# _AC_PROG_LIBTOOL
+
+
+# AC_LIBTOOL_SETUP
+# ----------------
+AC_DEFUN([AC_LIBTOOL_SETUP],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+AC_REQUIRE([AC_OBJEXT])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+dnl
+
+AC_LIBTOOL_SYS_MAX_CMD_LEN
+AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+AC_LIBTOOL_OBJDIR
+
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+_LT_AC_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
+
+# Same as above, but do not quote variable references.
+[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ AC_PATH_MAGIC
+ fi
+ ;;
+esac
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+enable_win32_dll=yes, enable_win32_dll=no)
+
+AC_ARG_ENABLE([libtool-lock],
+ [AC_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+AC_ARG_WITH([pic],
+ [AC_HELP_STRING([--with-pic],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [pic_mode="$withval"],
+ [pic_mode=default])
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+AC_LIBTOOL_LANG_C_CONFIG
+_LT_AC_TAGCONFIG
+])# AC_LIBTOOL_SETUP
+
+
+# _LT_AC_SYS_COMPILER
+# -------------------
+AC_DEFUN([_LT_AC_SYS_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_AC_SYS_COMPILER
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+AC_DEFUN([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+AC_DEFUN([_LT_LINKER_BOILERPLATE],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_LINKER_BOILERPLATE
+
+
+# _LT_AC_SYS_LIBPATH_AIX
+# ----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_AC_SYS_LIBPATH_AIX
+
+
+# _LT_AC_SHELL_INIT(ARG)
+# ----------------------
+AC_DEFUN([_LT_AC_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+ [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+ [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_AC_SHELL_INIT
+
+
+# _LT_AC_PROG_ECHO_BACKSLASH
+# --------------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+[_LT_AC_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+ ;;
+esac
+
+echo=${ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X[$]1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+[$]*
+EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+ echo_test_string=`eval $cmd` &&
+ (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+ then
+ break
+ fi
+ done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$echo" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ echo='print -r'
+ elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+ else
+ # Try using printf.
+ echo='printf %s\n'
+ if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ echo="$CONFIG_SHELL [$]0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$CONFIG_SHELL [$]0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+ if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "[$]0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ echo=echo
+ fi
+ fi
+ fi
+ fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+ ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(ECHO)
+])])# _LT_AC_PROG_ECHO_BACKSLASH
+
+
+# _LT_AC_LOCK
+# -----------
+AC_DEFUN([_LT_AC_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AC_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ libsuff=64
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *) LD="${LD-ld} -64" ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+ ])
+esac
+
+need_locks="$enable_libtool_lock"
+
+])# _LT_AC_LOCK
+
+
+# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $rm conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ ifelse([$5], , :, [$5])
+else
+ ifelse([$6], , :, [$6])
+fi
+])# AC_LIBTOOL_COMPILER_OPTION
+
+
+# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ ifelse([$4], , :, [$4])
+else
+ ifelse([$5], , :, [$5])
+fi
+])# AC_LIBTOOL_LINKER_OPTION
+
+
+# AC_LIBTOOL_SYS_MAX_CMD_LEN
+# --------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+[# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+ = "XX$teststring") >/dev/null 2>&1 &&
+ new_result=`expr "X$teststring" : ".*" 2>&1` &&
+ lt_cv_sys_max_cmd_len=$new_result &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on massive
+ # amounts of additional arguments before passing them to the linker.
+ # It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+
+
+# _LT_AC_CHECK_DLFCN
+# ------------------
+AC_DEFUN([_LT_AC_CHECK_DLFCN],
+[AC_CHECK_HEADERS(dlfcn.h)dnl
+])# _LT_AC_CHECK_DLFCN
+
+
+# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ---------------------------------------------------------------------
+AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ exit (status);
+}]
+EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_AC_TRY_DLOPEN_SELF
+
+
+# AC_LIBTOOL_DLOPEN_SELF
+# ----------------------
+AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_AC_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_AC_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+])# AC_LIBTOOL_DLOPEN_SELF
+
+
+# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+# ---------------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler
+AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+])
+])# AC_LIBTOOL_PROG_CC_C_O
+
+
+# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+# -----------------------------------------
+# Check to see if we can do hard links to lock some files if needed
+AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+[AC_REQUIRE([_LT_AC_LOCK])dnl
+
+hard_links="nottested"
+if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+
+
+# AC_LIBTOOL_OBJDIR
+# -----------------
+AC_DEFUN([AC_LIBTOOL_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+])# AC_LIBTOOL_OBJDIR
+
+
+# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+# ----------------------------------------------
+# Check hardcoding attributes.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_AC_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+ test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+ test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_AC_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_AC_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
+
+
+# AC_LIBTOOL_SYS_LIB_STRIP
+# ------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+[striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+])# AC_LIBTOOL_SYS_LIB_STRIP
+
+
+# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+m4_if($1,[],[
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ sys_lib_search_path_spec=`echo $lt_search_path_spec`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+ m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[123]]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ shlibpath_overrides_runpath=no
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ shlibpath_overrides_runpath=yes
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+
+
+# _LT_AC_TAGCONFIG
+# ----------------
+AC_DEFUN([_LT_AC_TAGCONFIG],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_ARG_WITH([tags],
+ [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+ [include additional configurations @<:@automatic@:>@])],
+ [tagnames="$withval"])
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+ if test ! -f "${ofile}"; then
+ AC_MSG_WARN([output file `$ofile' does not exist])
+ fi
+
+ if test -z "$LTCC"; then
+ eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+ if test -z "$LTCC"; then
+ AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+ else
+ AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+ fi
+ fi
+ if test -z "$LTCFLAGS"; then
+ eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
+ fi
+
+ # Extract list of available tagged configurations in $ofile.
+ # Note that this assumes the entire list is on one line.
+ available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for tagname in $tagnames; do
+ IFS="$lt_save_ifs"
+ # Check whether tagname contains only valid characters
+ case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+ "") ;;
+ *) AC_MSG_ERROR([invalid tag name: $tagname])
+ ;;
+ esac
+
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+ then
+ AC_MSG_ERROR([tag name \"$tagname\" already exists])
+ fi
+
+ # Update the list of available tags.
+ if test -n "$tagname"; then
+ echo appending configuration tag \"$tagname\" to $ofile
+
+ case $tagname in
+ CXX)
+ if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_LIBTOOL_LANG_CXX_CONFIG
+ else
+ tagname=""
+ fi
+ ;;
+
+ F77)
+ if test -n "$F77" && test "X$F77" != "Xno"; then
+ AC_LIBTOOL_LANG_F77_CONFIG
+ else
+ tagname=""
+ fi
+ ;;
+
+ GCJ)
+ if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+ AC_LIBTOOL_LANG_GCJ_CONFIG
+ else
+ tagname=""
+ fi
+ ;;
+
+ RC)
+ AC_LIBTOOL_LANG_RC_CONFIG
+ ;;
+
+ *)
+ AC_MSG_ERROR([Unsupported tag name: $tagname])
+ ;;
+ esac
+
+ # Append the new tag name to the list of available tags.
+ if test -n "$tagname" ; then
+ available_tags="$available_tags $tagname"
+ fi
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ # Now substitute the updated list of available tags.
+ if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+ mv "${ofile}T" "$ofile"
+ chmod +x "$ofile"
+ else
+ rm -f "${ofile}T"
+ AC_MSG_ERROR([unable to update list of available tagged configurations.])
+ fi
+fi
+])# _LT_AC_TAGCONFIG
+
+
+# AC_LIBTOOL_DLOPEN
+# -----------------
+# enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_DLOPEN
+
+
+# AC_LIBTOOL_WIN32_DLL
+# --------------------
+# declare package support for building win32 DLLs
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_WIN32_DLL
+
+
+# AC_ENABLE_SHARED([DEFAULT])
+# ---------------------------
+# implement the --enable-shared flag
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([shared],
+ [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+])# AC_ENABLE_SHARED
+
+
+# AC_DISABLE_SHARED
+# -----------------
+# set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)
+])# AC_DISABLE_SHARED
+
+
+# AC_ENABLE_STATIC([DEFAULT])
+# ---------------------------
+# implement the --enable-static flag
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([static],
+ [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+])# AC_ENABLE_STATIC
+
+
+# AC_DISABLE_STATIC
+# -----------------
+# set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)
+])# AC_DISABLE_STATIC
+
+
+# AC_ENABLE_FAST_INSTALL([DEFAULT])
+# ---------------------------------
+# implement the --enable-fast-install flag
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([fast-install],
+ [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+])# AC_ENABLE_FAST_INSTALL
+
+
+# AC_DISABLE_FAST_INSTALL
+# -----------------------
+# set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)
+])# AC_DISABLE_FAST_INSTALL
+
+
+# AC_LIBTOOL_PICMODE([MODE])
+# --------------------------
+# implement the --with-pic flag
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)
+])# AC_LIBTOOL_PICMODE
+
+
+# AC_PROG_EGREP
+# -------------
+# This is predefined starting with Autoconf 2.54, so this conditional
+# definition can be removed once we require Autoconf 2.54 or later.
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+ [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])])
+
+
+# AC_PATH_TOOL_PREFIX
+# -------------------
+# find a file program which can recognize shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="ifelse([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+])# AC_PATH_TOOL_PREFIX
+
+
+# AC_PATH_MAGIC
+# -------------
+# find a file program which can recognize a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# AC_PATH_MAGIC
+
+
+# AC_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+ [AC_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])
+AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])# AC_PROG_LD
+
+
+# AC_PROG_LD_GNU
+# --------------
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+
+# AC_PROG_LD_RELOAD_FLAG
+# ----------------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+])# AC_PROG_LD_RELOAD_FLAG
+
+
+# AC_DEPLIBS_CHECK_METHOD
+# -----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+nto-qnx*)
+ lt_cv_deplibs_check_method=unknown
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+])# AC_DEPLIBS_CHECK_METHOD
+
+
+# AC_PROG_NM
+# ----------
+# find the pathname to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+])# AC_PROG_NM
+
+
+# AC_CHECK_LIBM
+# -------------
+# check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+])# AC_CHECK_LIBM
+
+
+# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl convenience library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-convenience to the configure arguments. Note that
+# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided,
+# it is assumed to be `libltdl'. LIBLTDL will be prefixed with
+# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
+# (note the single quotes!). If your package is not flat and you're not
+# using automake, define top_builddir and top_srcdir appropriately in
+# the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ case $enable_ltdl_convenience in
+ no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+ "") enable_ltdl_convenience=yes
+ ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+ esac
+ LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+ LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+ # For backwards non-gettext consistent compatibility...
+ INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_CONVENIENCE
+
+
+# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl installable library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-install to the configure arguments. Note that
+# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided,
+# and an installed libltdl is not found, it is assumed to be `libltdl'.
+# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
+# '${top_srcdir}/' (note the single quotes!). If your package is not
+# flat and you're not using automake, define top_builddir and top_srcdir
+# appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+ AC_CHECK_LIB(ltdl, lt_dlinit,
+ [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+ [if test x"$enable_ltdl_install" = xno; then
+ AC_MSG_WARN([libltdl not installed, but installation disabled])
+ else
+ enable_ltdl_install=yes
+ fi
+ ])
+ if test x"$enable_ltdl_install" = x"yes"; then
+ ac_configure_args="$ac_configure_args --enable-ltdl-install"
+ LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+ LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+ else
+ ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+ LIBLTDL="-lltdl"
+ LTDLINCL=
+ fi
+ # For backwards non-gettext consistent compatibility...
+ INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_INSTALLABLE
+
+
+# AC_LIBTOOL_CXX
+# --------------
+# enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX],
+[AC_REQUIRE([_LT_AC_LANG_CXX])
+])# AC_LIBTOOL_CXX
+
+
+# _LT_AC_LANG_CXX
+# ---------------
+AC_DEFUN([_LT_AC_LANG_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+])# _LT_AC_LANG_CXX
+
+# _LT_AC_PROG_CXXCPP
+# ------------------
+AC_DEFUN([_LT_AC_PROG_CXXCPP],
+[
+AC_REQUIRE([AC_PROG_CXX])
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+fi
+])# _LT_AC_PROG_CXXCPP
+
+# AC_LIBTOOL_F77
+# --------------
+# enable support for Fortran 77 libraries
+AC_DEFUN([AC_LIBTOOL_F77],
+[AC_REQUIRE([_LT_AC_LANG_F77])
+])# AC_LIBTOOL_F77
+
+
+# _LT_AC_LANG_F77
+# ---------------
+AC_DEFUN([_LT_AC_LANG_F77],
+[AC_REQUIRE([AC_PROG_F77])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+])# _LT_AC_LANG_F77
+
+
+# AC_LIBTOOL_GCJ
+# --------------
+# enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],
+[AC_REQUIRE([_LT_AC_LANG_GCJ])
+])# AC_LIBTOOL_GCJ
+
+
+# _LT_AC_LANG_GCJ
+# ---------------
+AC_DEFUN([_LT_AC_LANG_GCJ],
+[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+ [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+ [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+ [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+ [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+])# _LT_AC_LANG_GCJ
+
+
+# AC_LIBTOOL_RC
+# -------------
+# enable support for Windows resource files
+AC_DEFUN([AC_LIBTOOL_RC],
+[AC_REQUIRE([LT_AC_PROG_RC])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+])# AC_LIBTOOL_RC
+
+
+# AC_LIBTOOL_LANG_C_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+[lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF
+
+# Report which library types will actually be built
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_C_CONFIG
+
+
+# AC_LIBTOOL_LANG_CXX_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+[AC_LANG_PUSH(C++)
+AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Dependencies to place before and after the object being linked:
+_LT_AC_TAGVAR(predep_objects, $1)=
+_LT_AC_TAGVAR(postdep_objects, $1)=
+_LT_AC_TAGVAR(predeps, $1)=
+_LT_AC_TAGVAR(postdeps, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+ $as_unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+ $as_unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+else
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+fi
+
+if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ AC_PROG_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+ grep 'no-whole-archive' > /dev/null; then
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_AC_TAGVAR(archive_cmds, $1)=''
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(always_export_symbols, $1)=no
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+ if test "$GXX" = yes ; then
+ lt_int_apple_cc_single_mod=no
+ output_verbose_link_cmd='echo'
+ if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+ lt_int_apple_cc_single_mod=yes
+ fi
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ fi
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring'
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ freebsd[[12]]*)
+ # C++ shared libraries reported to be fairly broken before switch to ELF
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ freebsd-elf*)
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+ gnu*)
+ ;;
+ hpux9*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*) ;;
+ *)
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ interix[[3-9]]*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+ fi
+ fi
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc*)
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC*)
+ # Portland Group C++ compiler
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='echo'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd='echo'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ osf3*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~
+ $rm $lib.exp'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='echo'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | grep -v '^2\.7' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+ fi
+
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ # So that behaviour is only enabled if SCOABSPATH is set to a
+ # non-empty value in the environment. Most likely only useful for
+ # creating official distributions of packages.
+ # This is a hack until libtool officially supports absolute path
+ # names for shared libraries.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+esac
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$GXX"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_POSTDEP_PREDEP($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+])# AC_LIBTOOL_LANG_CXX_CONFIG
+
+# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+# ------------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+int a;
+void foo (void) { a = 0; }
+EOF
+],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+EOF
+],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+EOF
+],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ # The `*' in the case matches for architectures that use `case' in
+ # $output_verbose_cmd can trigger glob expansion during the loop
+ # eval without this substitution.
+ output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
+
+ for p in `eval $output_verbose_link_cmd`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" \
+ || test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+ _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+ _LT_AC_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+ _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$rm -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+ifelse([$1],[CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_AC_TAGVAR(predep_objects,$1)=
+ _LT_AC_TAGVAR(postdep_objects,$1)=
+ _LT_AC_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ #
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_AC_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+])# AC_LIBTOOL_POSTDEP_PREDEP
+
+# AC_LIBTOOL_LANG_F77_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+[AC_REQUIRE([AC_PROG_F77])
+AC_LANG_PUSH(Fortran 77)
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="\
+ program t
+ end
+"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+_LT_AC_TAGVAR(GCC, $1)="$G77"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_F77_CONFIG
+
+
+# AC_LIBTOOL_LANG_GCJ_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_GCJ_CONFIG
+
+
+# AC_LIBTOOL_LANG_RC_CONFIG
+# -------------------------
+# Ensure that the configuration vars for the Windows resource compiler are
+# suitably defined. Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_RC_CONFIG
+
+
+# AC_LIBTOOL_CONFIG([TAGNAME])
+# ----------------------------
+# If TAGNAME is not passed, then create an initial libtool script
+# with a default configuration from the untagged config vars. Otherwise
+# add code to config.status for appending the configuration named by
+# TAGNAME from the matching tagged config vars.
+AC_DEFUN([AC_LIBTOOL_CONFIG],
+[# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ _LT_AC_TAGVAR(compiler, $1) \
+ _LT_AC_TAGVAR(CC, $1) \
+ _LT_AC_TAGVAR(LD, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+ _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+ _LT_AC_TAGVAR(old_archive_cmds, $1) \
+ _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+ _LT_AC_TAGVAR(predep_objects, $1) \
+ _LT_AC_TAGVAR(postdep_objects, $1) \
+ _LT_AC_TAGVAR(predeps, $1) \
+ _LT_AC_TAGVAR(postdeps, $1) \
+ _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+ _LT_AC_TAGVAR(archive_cmds, $1) \
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+ _LT_AC_TAGVAR(postinstall_cmds, $1) \
+ _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+ _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+ _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+ _LT_AC_TAGVAR(no_undefined_flag, $1) \
+ _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+ _LT_AC_TAGVAR(hardcode_automatic, $1) \
+ _LT_AC_TAGVAR(module_cmds, $1) \
+ _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+ _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+ _LT_AC_TAGVAR(fix_srcfile_path, $1) \
+ _LT_AC_TAGVAR(exclude_expsyms, $1) \
+ _LT_AC_TAGVAR(include_expsyms, $1); do
+
+ case $var in
+ _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+ _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+ _LT_AC_TAGVAR(archive_cmds, $1) | \
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+ _LT_AC_TAGVAR(module_cmds, $1) | \
+ _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+ _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+ _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\[$]0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
+ ;;
+ esac
+
+ifelse([$1], [],
+ [cfgfile="${ofile}T"
+ trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+ $rm -f "$cfgfile"
+ AC_MSG_NOTICE([creating $ofile])],
+ [cfgfile="$ofile"])
+
+ cat <<__EOF__ >> "$cfgfile"
+ifelse([$1], [],
+[#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e 1s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG],
+[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
+# A language-specific compiler.
+CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
+
+# Is the compiler the GNU C compiler?
+with_gcc=$_LT_AC_TAGVAR(GCC, $1)
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
+
+# Symbols that must always be exported.
+include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
+
+ifelse([$1],[],
+[# ### END LIBTOOL CONFIG],
+[# ### END LIBTOOL TAG CONFIG: $tagname])
+
+__EOF__
+
+ifelse([$1],[], [
+ case $host_os in
+ aix3*)
+ cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+EOF
+ ;;
+ esac
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" || \
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+])
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+])# AC_LIBTOOL_CONFIG
+
+
+# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+
+_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+ AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
+
+
+# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+# ---------------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+[AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([LT_AC_PROG_SED])
+AC_REQUIRE([AC_PROG_NM])
+AC_REQUIRE([AC_OBJEXT])
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*) # Its linker distinguishes data from code symbols
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ ;;
+linux* | k*bsd*-gnu)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDGIRSTW]]'
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if grep ' nm_test_var$' "$nlist" >/dev/null; then
+ if grep ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+ cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[[]] =
+{
+EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+ cat <<\EOF >> conftest.$ac_ext
+ {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -f conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+
+
+# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+# ---------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+ ifelse([$1],[CXX],[
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix4* | aix5*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ icpc* | ecpc*)
+ # Intel C++
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC*)
+ # Portland Group C++ compiler.
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ newsos6)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ icc* | ecc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Sun\ F*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+ _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+ [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\"
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+])
+
+
+# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+# ------------------------------------
+# See if the linker supports building shared libraries.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ifelse([$1],[CXX],[
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix4* | aix5*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw*)
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+],[
+ runpath_var=
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_AC_TAGVAR(archive_cmds, $1)=
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+ _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+ _LT_AC_TAGVAR(module_cmds, $1)=
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+ _LT_AC_TAGVAR(always_export_symbols, $1)=no
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_AC_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+ # Just being paranoid about ensuring that cc_basename is set.
+ _LT_CC_BASENAME([$compiler])
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(always_export_symbols, $1)=no
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ interix[[3-9]]*)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | k*bsd*-gnu)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ *)
+ tmp_sharedflag='-shared' ;;
+ esac
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test $supports_anon_versioning = yes; then
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ $echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_AC_TAGVAR(archive_cmds, $1)=''
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ _LT_AC_SYS_LIBPATH_AIX
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ # see comment about different semantics on the GNU ld section
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ bsdi[[45]]*)
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_AC_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+ _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ darwin* | rhapsody*)
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[[012]])
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring'
+ _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ freebsd1*)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ wlarc=''
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+ _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_AC_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_AC_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+ $rm conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+ then
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+ ;;
+ esac
+ fi
+ ;;
+esac
+])# AC_LIBTOOL_PROG_LD_SHLIBS
+
+
+# _LT_AC_FILE_LTDLL_C
+# -------------------
+# Be careful that the start marker always follows a newline.
+AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# # ifdef __CYGWIN32__
+# # define __CYGWIN__ __CYGWIN32__
+# # endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+# __hDllInstance_base = hInst;
+# return TRUE;
+# }
+# /* ltdll.c ends here */
+])# _LT_AC_FILE_LTDLL_C
+
+
+# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+# ---------------------------------
+AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
+
+
+# old names
+AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL])
+AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+AC_DEFUN([AM_PROG_LD], [AC_PROG_LD])
+AC_DEFUN([AM_PROG_NM], [AC_PROG_NM])
+
+# This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)
+])
+
+AC_DEFUN([LT_AC_PROG_RC],
+[AC_CHECK_TOOL(RC, windres, no)
+])
+
+
+# Cheap backport of AS_EXECUTABLE_P and required macros
+# from Autoconf 2.59; we should not use $as_executable_p directly.
+
+# _AS_TEST_PREPARE
+# ----------------
+m4_ifndef([_AS_TEST_PREPARE],
+[m4_defun([_AS_TEST_PREPARE],
+[if test -x / >/dev/null 2>&1; then
+ as_executable_p='test -x'
+else
+ as_executable_p='test -f'
+fi
+])])# _AS_TEST_PREPARE
+
+# AS_EXECUTABLE_P
+# ---------------
+# Check whether a file is executable.
+m4_ifndef([AS_EXECUTABLE_P],
+[m4_defun([AS_EXECUTABLE_P],
+[AS_REQUIRE([_AS_TEST_PREPARE])dnl
+$as_executable_p $1[]dnl
+])])# AS_EXECUTABLE_P
+
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+# LT_AC_PROG_SED
+# --------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+AC_DEFUN([LT_AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if AS_EXECUTABLE_P(["$as_dir/$lt_ac_prog$ac_exec_ext"]); then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])
+
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+ [AC_MSG_RESULT([no])
+ $4])
+elif test $pkg_failed = untried; then
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
+ [$4])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.10'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.10.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.10.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 3
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 13
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.60])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_PROG_LEX
+# -----------
+# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a
+# "missing" invocation, for better error output.
+AC_DEFUN([AM_PROG_LEX],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AM_MISSING_HAS_RUN])dnl
+AC_REQUIRE([AC_PROG_LEX])dnl
+if test "$LEX" = :; then
+ LEX=${am_missing_run}flex
+fi])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+AC_DEFUN([AM_MAINTAINER_MODE],
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([acinclude.m4])
diff --git a/utils/audio/Makefile.am b/utils/audio/Makefile.am
new file mode 100644
index 00000000..0c6acfab
--- /dev/null
+++ b/utils/audio/Makefile.am
@@ -0,0 +1,62 @@
+
+if AUDIOPLUGIN
+plugindir = $(libdir)/bluetooth/plugins
+
+plugin_LTLIBRARIES = audio.la
+
+audio_la_SOURCES = main.c \
+ manager.h manager.c headset.h headset.c \
+ ipc.h ipc.c unix.h unix.c \
+ device.h device.c gateway.h gateway.c \
+ sink.c sink.h avdtp.c avdtp.h \
+ a2dp.c a2dp.h control.c control.h
+
+audio_la_LDFLAGS = -module -avoid-version -no-undefined \
+ -export-symbols-regex bluetooth_plugin_desc
+
+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@ @ALSA_LIBS@
+libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_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 = @ALSA_LIBS@
+libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+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 -export-symbols-regex gst_plugin_desc
+libgstbluetooth_la_LIBADD = @SBC_LIBS@ @GSTREAMER_LIBS@ -lgstaudio-0.10 -lgstrtp-0.10
+libgstbluetooth_la_CFLAGS = @GSTREAMER_CFLAGS@ @SBC_CFLAGS@
+endif
+endif
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -I$(top_srcdir)/sdpd
+
+EXTRA_DIST = audio.conf audio-api.txt test-audio asound.conf
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/audio/Makefile.in b/utils/audio/Makefile.in
new file mode 100644
index 00000000..dab0d43a
--- /dev/null
+++ b/utils/audio/Makefile.in
@@ -0,0 +1,774 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = audio
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(alsadir)" "$(DESTDIR)$(gstreamerdir)" \
+ "$(DESTDIR)$(plugindir)"
+alsaLTLIBRARIES_INSTALL = $(INSTALL)
+gstreamerLTLIBRARIES_INSTALL = $(INSTALL)
+pluginLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(alsa_LTLIBRARIES) $(gstreamer_LTLIBRARIES) \
+ $(plugin_LTLIBRARIES)
+audio_la_LIBADD =
+am__audio_la_SOURCES_DIST = main.c manager.h manager.c headset.h \
+ headset.c ipc.h ipc.c unix.h unix.c device.h device.c \
+ gateway.h gateway.c sink.c sink.h avdtp.c avdtp.h a2dp.c \
+ a2dp.h control.c control.h
+@AUDIOPLUGIN_TRUE@am_audio_la_OBJECTS = main.lo manager.lo headset.lo \
+@AUDIOPLUGIN_TRUE@ ipc.lo unix.lo device.lo gateway.lo sink.lo \
+@AUDIOPLUGIN_TRUE@ avdtp.lo a2dp.lo control.lo
+audio_la_OBJECTS = $(am_audio_la_OBJECTS)
+audio_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(audio_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@AUDIOPLUGIN_TRUE@am_audio_la_rpath = -rpath $(plugindir)
+libasound_module_ctl_bluetooth_la_DEPENDENCIES =
+am__libasound_module_ctl_bluetooth_la_SOURCES_DIST = ctl_bluetooth.c \
+ rtp.h ipc.h ipc.c
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@am_libasound_module_ctl_bluetooth_la_OBJECTS = libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo \
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@ libasound_module_ctl_bluetooth_la-ipc.lo
+libasound_module_ctl_bluetooth_la_OBJECTS = \
+ $(am_libasound_module_ctl_bluetooth_la_OBJECTS)
+libasound_module_ctl_bluetooth_la_LINK = $(LIBTOOL) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) \
+ $(libasound_module_ctl_bluetooth_la_LDFLAGS) $(LDFLAGS) -o $@
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@am_libasound_module_ctl_bluetooth_la_rpath = \
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@ -rpath $(alsadir)
+libasound_module_pcm_bluetooth_la_DEPENDENCIES =
+am__libasound_module_pcm_bluetooth_la_SOURCES_DIST = pcm_bluetooth.c \
+ rtp.h ipc.h ipc.c
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@am_libasound_module_pcm_bluetooth_la_OBJECTS = libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo \
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@ libasound_module_pcm_bluetooth_la-ipc.lo
+libasound_module_pcm_bluetooth_la_OBJECTS = \
+ $(am_libasound_module_pcm_bluetooth_la_OBJECTS)
+libasound_module_pcm_bluetooth_la_LINK = $(LIBTOOL) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) \
+ $(libasound_module_pcm_bluetooth_la_LDFLAGS) $(LDFLAGS) -o $@
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@am_libasound_module_pcm_bluetooth_la_rpath = \
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@ -rpath $(alsadir)
+libgstbluetooth_la_DEPENDENCIES =
+am__libgstbluetooth_la_SOURCES_DIST = 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
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@am_libgstbluetooth_la_OBJECTS = libgstbluetooth_la-gstbluetooth.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-gstsbcenc.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-gstsbcdec.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-gstsbcparse.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-gstavdtpsink.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-gsta2dpsink.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-gstsbcutil.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-gstrtpsbcpay.lo \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ libgstbluetooth_la-ipc.lo
+libgstbluetooth_la_OBJECTS = $(am_libgstbluetooth_la_OBJECTS)
+libgstbluetooth_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libgstbluetooth_la_CFLAGS) $(CFLAGS) \
+ $(libgstbluetooth_la_LDFLAGS) $(LDFLAGS) -o $@
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@am_libgstbluetooth_la_rpath = \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ -rpath $(gstreamerdir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(audio_la_SOURCES) \
+ $(libasound_module_ctl_bluetooth_la_SOURCES) \
+ $(libasound_module_pcm_bluetooth_la_SOURCES) \
+ $(libgstbluetooth_la_SOURCES)
+DIST_SOURCES = $(am__audio_la_SOURCES_DIST) \
+ $(am__libasound_module_ctl_bluetooth_la_SOURCES_DIST) \
+ $(am__libasound_module_pcm_bluetooth_la_SOURCES_DIST) \
+ $(am__libgstbluetooth_la_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@AUDIOPLUGIN_TRUE@plugindir = $(libdir)/bluetooth/plugins
+@AUDIOPLUGIN_TRUE@plugin_LTLIBRARIES = audio.la
+@AUDIOPLUGIN_TRUE@audio_la_SOURCES = main.c \
+@AUDIOPLUGIN_TRUE@ manager.h manager.c headset.h headset.c \
+@AUDIOPLUGIN_TRUE@ ipc.h ipc.c unix.h unix.c \
+@AUDIOPLUGIN_TRUE@ device.h device.c gateway.h gateway.c \
+@AUDIOPLUGIN_TRUE@ sink.c sink.h avdtp.c avdtp.h \
+@AUDIOPLUGIN_TRUE@ a2dp.c a2dp.h control.c control.h
+
+@AUDIOPLUGIN_TRUE@audio_la_LDFLAGS = -module -avoid-version -no-undefined \
+@AUDIOPLUGIN_TRUE@ -export-symbols-regex bluetooth_plugin_desc
+
+@AUDIOPLUGIN_TRUE@LDADD = $(top_builddir)/common/libhelper.a \
+@AUDIOPLUGIN_TRUE@ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@alsadir = $(libdir)/alsa-lib
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@alsa_LTLIBRARIES = libasound_module_pcm_bluetooth.la libasound_module_ctl_bluetooth.la
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c rtp.h ipc.h ipc.c
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version -export-symbols-regex [_]*snd_pcm_.*
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_pcm_bluetooth_la_LIBADD = @SBC_LIBS@ @ALSA_LIBS@
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @SBC_CFLAGS@
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c rtp.h ipc.h ipc.c
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version -export-symbols-regex [_]*snd_ctl_.*
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_ctl_bluetooth_la_LIBADD = @ALSA_LIBS@
+@ALSA_TRUE@@AUDIOPLUGIN_TRUE@libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@gstreamerdir = $(libdir)/gstreamer-0.10
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@gstreamer_LTLIBRARIES = libgstbluetooth.la
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@libgstbluetooth_la_SOURCES = gstbluetooth.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ gstsbcenc.h gstsbcenc.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ gstsbcdec.h gstsbcdec.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ gstsbcparse.h gstsbcparse.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ gstavdtpsink.h gstavdtpsink.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ gsta2dpsink.h gsta2dpsink.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ gstsbcutil.h gstsbcutil.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ gstrtpsbcpay.h gstrtpsbcpay.c \
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ rtp.h ipc.h ipc.c
+
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@libgstbluetooth_la_LDFLAGS = -module -avoid-version -export-symbols-regex gst_plugin_desc
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@libgstbluetooth_la_LIBADD = @SBC_LIBS@ @GSTREAMER_LIBS@ -lgstaudio-0.10 -lgstrtp-0.10
+@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@libgstbluetooth_la_CFLAGS = @GSTREAMER_CFLAGS@ @SBC_CFLAGS@
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -I$(top_srcdir)/sdpd
+EXTRA_DIST = audio.conf audio-api.txt test-audio asound.conf
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu audio/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu audio/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-alsaLTLIBRARIES: $(alsa_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(alsadir)" || $(MKDIR_P) "$(DESTDIR)$(alsadir)"
+ @list='$(alsa_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(alsaLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(alsadir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(alsaLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(alsadir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-alsaLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(alsa_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(alsadir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(alsadir)/$$p"; \
+ done
+
+clean-alsaLTLIBRARIES:
+ -test -z "$(alsa_LTLIBRARIES)" || rm -f $(alsa_LTLIBRARIES)
+ @list='$(alsa_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+install-gstreamerLTLIBRARIES: $(gstreamer_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(gstreamerdir)" || $(MKDIR_P) "$(DESTDIR)$(gstreamerdir)"
+ @list='$(gstreamer_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(gstreamerLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(gstreamerdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(gstreamerLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(gstreamerdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-gstreamerLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(gstreamer_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(gstreamerdir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(gstreamerdir)/$$p"; \
+ done
+
+clean-gstreamerLTLIBRARIES:
+ -test -z "$(gstreamer_LTLIBRARIES)" || rm -f $(gstreamer_LTLIBRARIES)
+ @list='$(gstreamer_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+audio.la: $(audio_la_OBJECTS) $(audio_la_DEPENDENCIES)
+ $(audio_la_LINK) $(am_audio_la_rpath) $(audio_la_OBJECTS) $(audio_la_LIBADD) $(LIBS)
+libasound_module_ctl_bluetooth.la: $(libasound_module_ctl_bluetooth_la_OBJECTS) $(libasound_module_ctl_bluetooth_la_DEPENDENCIES)
+ $(libasound_module_ctl_bluetooth_la_LINK) $(am_libasound_module_ctl_bluetooth_la_rpath) $(libasound_module_ctl_bluetooth_la_OBJECTS) $(libasound_module_ctl_bluetooth_la_LIBADD) $(LIBS)
+libasound_module_pcm_bluetooth.la: $(libasound_module_pcm_bluetooth_la_OBJECTS) $(libasound_module_pcm_bluetooth_la_DEPENDENCIES)
+ $(libasound_module_pcm_bluetooth_la_LINK) $(am_libasound_module_pcm_bluetooth_la_rpath) $(libasound_module_pcm_bluetooth_la_OBJECTS) $(libasound_module_pcm_bluetooth_la_LIBADD) $(LIBS)
+libgstbluetooth.la: $(libgstbluetooth_la_OBJECTS) $(libgstbluetooth_la_DEPENDENCIES)
+ $(libgstbluetooth_la_LINK) $(am_libgstbluetooth_la_rpath) $(libgstbluetooth_la_OBJECTS) $(libgstbluetooth_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/a2dp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avdtp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gateway.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/headset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasound_module_ctl_bluetooth_la-ctl_bluetooth.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasound_module_ctl_bluetooth_la-ipc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasound_module_pcm_bluetooth_la-ipc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libasound_module_pcm_bluetooth_la-pcm_bluetooth.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gsta2dpsink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gstavdtpsink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gstbluetooth.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gstrtpsbcpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gstsbcdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gstsbcenc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gstsbcparse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-gstsbcutil.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbluetooth_la-ipc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo: ctl_bluetooth.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -MT libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo -MD -MP -MF $(DEPDIR)/libasound_module_ctl_bluetooth_la-ctl_bluetooth.Tpo -c -o libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo `test -f 'ctl_bluetooth.c' || echo '$(srcdir)/'`ctl_bluetooth.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libasound_module_ctl_bluetooth_la-ctl_bluetooth.Tpo $(DEPDIR)/libasound_module_ctl_bluetooth_la-ctl_bluetooth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ctl_bluetooth.c' object='libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -c -o libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo `test -f 'ctl_bluetooth.c' || echo '$(srcdir)/'`ctl_bluetooth.c
+
+libasound_module_ctl_bluetooth_la-ipc.lo: ipc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -MT libasound_module_ctl_bluetooth_la-ipc.lo -MD -MP -MF $(DEPDIR)/libasound_module_ctl_bluetooth_la-ipc.Tpo -c -o libasound_module_ctl_bluetooth_la-ipc.lo `test -f 'ipc.c' || echo '$(srcdir)/'`ipc.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libasound_module_ctl_bluetooth_la-ipc.Tpo $(DEPDIR)/libasound_module_ctl_bluetooth_la-ipc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ipc.c' object='libasound_module_ctl_bluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -c -o libasound_module_ctl_bluetooth_la-ipc.lo `test -f 'ipc.c' || echo '$(srcdir)/'`ipc.c
+
+libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo: pcm_bluetooth.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -MT libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo -MD -MP -MF $(DEPDIR)/libasound_module_pcm_bluetooth_la-pcm_bluetooth.Tpo -c -o libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo `test -f 'pcm_bluetooth.c' || echo '$(srcdir)/'`pcm_bluetooth.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libasound_module_pcm_bluetooth_la-pcm_bluetooth.Tpo $(DEPDIR)/libasound_module_pcm_bluetooth_la-pcm_bluetooth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pcm_bluetooth.c' object='libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -c -o libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo `test -f 'pcm_bluetooth.c' || echo '$(srcdir)/'`pcm_bluetooth.c
+
+libasound_module_pcm_bluetooth_la-ipc.lo: ipc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -MT libasound_module_pcm_bluetooth_la-ipc.lo -MD -MP -MF $(DEPDIR)/libasound_module_pcm_bluetooth_la-ipc.Tpo -c -o libasound_module_pcm_bluetooth_la-ipc.lo `test -f 'ipc.c' || echo '$(srcdir)/'`ipc.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libasound_module_pcm_bluetooth_la-ipc.Tpo $(DEPDIR)/libasound_module_pcm_bluetooth_la-ipc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ipc.c' object='libasound_module_pcm_bluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -c -o libasound_module_pcm_bluetooth_la-ipc.lo `test -f 'ipc.c' || echo '$(srcdir)/'`ipc.c
+
+libgstbluetooth_la-gstbluetooth.lo: gstbluetooth.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gstbluetooth.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gstbluetooth.Tpo -c -o libgstbluetooth_la-gstbluetooth.lo `test -f 'gstbluetooth.c' || echo '$(srcdir)/'`gstbluetooth.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gstbluetooth.Tpo $(DEPDIR)/libgstbluetooth_la-gstbluetooth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstbluetooth.c' object='libgstbluetooth_la-gstbluetooth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gstbluetooth.lo `test -f 'gstbluetooth.c' || echo '$(srcdir)/'`gstbluetooth.c
+
+libgstbluetooth_la-gstsbcenc.lo: gstsbcenc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gstsbcenc.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gstsbcenc.Tpo -c -o libgstbluetooth_la-gstsbcenc.lo `test -f 'gstsbcenc.c' || echo '$(srcdir)/'`gstsbcenc.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gstsbcenc.Tpo $(DEPDIR)/libgstbluetooth_la-gstsbcenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstsbcenc.c' object='libgstbluetooth_la-gstsbcenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gstsbcenc.lo `test -f 'gstsbcenc.c' || echo '$(srcdir)/'`gstsbcenc.c
+
+libgstbluetooth_la-gstsbcdec.lo: gstsbcdec.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gstsbcdec.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gstsbcdec.Tpo -c -o libgstbluetooth_la-gstsbcdec.lo `test -f 'gstsbcdec.c' || echo '$(srcdir)/'`gstsbcdec.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gstsbcdec.Tpo $(DEPDIR)/libgstbluetooth_la-gstsbcdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstsbcdec.c' object='libgstbluetooth_la-gstsbcdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gstsbcdec.lo `test -f 'gstsbcdec.c' || echo '$(srcdir)/'`gstsbcdec.c
+
+libgstbluetooth_la-gstsbcparse.lo: gstsbcparse.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gstsbcparse.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gstsbcparse.Tpo -c -o libgstbluetooth_la-gstsbcparse.lo `test -f 'gstsbcparse.c' || echo '$(srcdir)/'`gstsbcparse.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gstsbcparse.Tpo $(DEPDIR)/libgstbluetooth_la-gstsbcparse.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstsbcparse.c' object='libgstbluetooth_la-gstsbcparse.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gstsbcparse.lo `test -f 'gstsbcparse.c' || echo '$(srcdir)/'`gstsbcparse.c
+
+libgstbluetooth_la-gstavdtpsink.lo: gstavdtpsink.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gstavdtpsink.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gstavdtpsink.Tpo -c -o libgstbluetooth_la-gstavdtpsink.lo `test -f 'gstavdtpsink.c' || echo '$(srcdir)/'`gstavdtpsink.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gstavdtpsink.Tpo $(DEPDIR)/libgstbluetooth_la-gstavdtpsink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstavdtpsink.c' object='libgstbluetooth_la-gstavdtpsink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gstavdtpsink.lo `test -f 'gstavdtpsink.c' || echo '$(srcdir)/'`gstavdtpsink.c
+
+libgstbluetooth_la-gsta2dpsink.lo: gsta2dpsink.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gsta2dpsink.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gsta2dpsink.Tpo -c -o libgstbluetooth_la-gsta2dpsink.lo `test -f 'gsta2dpsink.c' || echo '$(srcdir)/'`gsta2dpsink.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gsta2dpsink.Tpo $(DEPDIR)/libgstbluetooth_la-gsta2dpsink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsta2dpsink.c' object='libgstbluetooth_la-gsta2dpsink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gsta2dpsink.lo `test -f 'gsta2dpsink.c' || echo '$(srcdir)/'`gsta2dpsink.c
+
+libgstbluetooth_la-gstsbcutil.lo: gstsbcutil.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gstsbcutil.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gstsbcutil.Tpo -c -o libgstbluetooth_la-gstsbcutil.lo `test -f 'gstsbcutil.c' || echo '$(srcdir)/'`gstsbcutil.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gstsbcutil.Tpo $(DEPDIR)/libgstbluetooth_la-gstsbcutil.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstsbcutil.c' object='libgstbluetooth_la-gstsbcutil.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gstsbcutil.lo `test -f 'gstsbcutil.c' || echo '$(srcdir)/'`gstsbcutil.c
+
+libgstbluetooth_la-gstrtpsbcpay.lo: gstrtpsbcpay.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-gstrtpsbcpay.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-gstrtpsbcpay.Tpo -c -o libgstbluetooth_la-gstrtpsbcpay.lo `test -f 'gstrtpsbcpay.c' || echo '$(srcdir)/'`gstrtpsbcpay.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-gstrtpsbcpay.Tpo $(DEPDIR)/libgstbluetooth_la-gstrtpsbcpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstrtpsbcpay.c' object='libgstbluetooth_la-gstrtpsbcpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-gstrtpsbcpay.lo `test -f 'gstrtpsbcpay.c' || echo '$(srcdir)/'`gstrtpsbcpay.c
+
+libgstbluetooth_la-ipc.lo: ipc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT libgstbluetooth_la-ipc.lo -MD -MP -MF $(DEPDIR)/libgstbluetooth_la-ipc.Tpo -c -o libgstbluetooth_la-ipc.lo `test -f 'ipc.c' || echo '$(srcdir)/'`ipc.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libgstbluetooth_la-ipc.Tpo $(DEPDIR)/libgstbluetooth_la-ipc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ipc.c' object='libgstbluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o libgstbluetooth_la-ipc.lo `test -f 'ipc.c' || echo '$(srcdir)/'`ipc.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(alsadir)" "$(DESTDIR)$(gstreamerdir)" "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-alsaLTLIBRARIES clean-generic \
+ clean-gstreamerLTLIBRARIES clean-libtool \
+ clean-pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-alsaLTLIBRARIES install-gstreamerLTLIBRARIES \
+ install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-alsaLTLIBRARIES uninstall-gstreamerLTLIBRARIES \
+ uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean \
+ clean-alsaLTLIBRARIES clean-generic clean-gstreamerLTLIBRARIES \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-alsaLTLIBRARIES install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-gstreamerLTLIBRARIES install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-alsaLTLIBRARIES uninstall-am \
+ uninstall-gstreamerLTLIBRARIES uninstall-pluginLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/audio/a2dp.c b/utils/audio/a2dp.c
new file mode 100644
index 00000000..3e89d6b1
--- /dev/null
+++ b/utils/audio/a2dp.c
@@ -0,0 +1,1470 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "logging.h"
+#include "device.h"
+#include "manager.h"
+#include "avdtp.h"
+#include "sink.h"
+#include "a2dp.h"
+#include "sdpd.h"
+
+/* The duration that streams without users are allowed to stay in
+ * STREAMING state. */
+#define SUSPEND_TIMEOUT 5000
+#define RECONFIGURE_TIMEOUT 500
+
+#ifndef MIN
+# define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+#ifndef MAX
+# define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+struct a2dp_sep {
+ uint8_t type;
+ uint8_t codec;
+ struct avdtp_local_sep *sep;
+ struct avdtp *session;
+ struct avdtp_stream *stream;
+ guint suspend_timer;
+ gboolean locked;
+ gboolean suspending;
+ gboolean starting;
+};
+
+struct a2dp_setup_cb {
+ a2dp_config_cb_t config_cb;
+ a2dp_stream_cb_t resume_cb;
+ a2dp_stream_cb_t suspend_cb;
+ void *user_data;
+ int id;
+};
+
+struct a2dp_setup {
+ struct avdtp *session;
+ struct a2dp_sep *sep;
+ struct avdtp_stream *stream;
+ struct avdtp_error *err;
+ GSList *client_caps;
+ gboolean reconfigure;
+ gboolean canceled;
+ gboolean start;
+ GSList *cb;
+ int ref;
+};
+
+static DBusConnection *connection = NULL;
+
+static GSList *sinks = NULL;
+static GSList *sources = NULL;
+
+static uint32_t source_record_id = 0;
+static uint32_t sink_record_id = 0;
+
+static GSList *setups = NULL;
+static unsigned int cb_id = 0;
+
+static struct a2dp_setup *setup_ref(struct a2dp_setup *setup)
+{
+ setup->ref++;
+
+ debug("setup_ref(%p): ref=%d", setup, setup->ref);
+
+ return setup;
+}
+
+static void setup_free(struct a2dp_setup *s)
+{
+ debug("setup_free(%p)", s);
+ setups = g_slist_remove(setups, s);
+ if (s->session)
+ avdtp_unref(s->session);
+ g_slist_foreach(s->cb, (GFunc) g_free, NULL);
+ g_slist_free(s->cb);
+ g_free(s);
+}
+
+static void setup_unref(struct a2dp_setup *setup)
+{
+ setup->ref--;
+
+ debug("setup_unref(%p): ref=%d", setup, setup->ref);
+
+ if (setup->ref <= 0)
+ setup_free(setup);
+}
+
+static struct audio_device *a2dp_get_dev(struct avdtp *session)
+{
+ bdaddr_t addr;
+
+ avdtp_get_peers(session, NULL, &addr);
+
+ return manager_device_connected(&addr, A2DP_SOURCE_UUID);
+}
+
+static gboolean finalize_config(struct a2dp_setup *s)
+{
+ GSList *l;
+
+ setup_ref(s);
+ for (l = s->cb; l != NULL; l = l->next) {
+ struct a2dp_setup_cb *cb = l->data;
+
+ if (cb->config_cb) {
+ cb->config_cb(s->session, s->sep, s->stream, s->err,
+ cb->user_data);
+ cb->config_cb = NULL;
+ setup_unref(s);
+ }
+ }
+
+ setup_unref(s);
+ return FALSE;
+}
+
+static gboolean finalize_config_errno(struct a2dp_setup *s, int err)
+{
+ struct avdtp_error avdtp_err;
+
+ avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
+ s->err = err ? &avdtp_err : NULL;
+
+ return finalize_config(s);
+}
+
+static gboolean finalize_resume(struct a2dp_setup *s)
+{
+ GSList *l;
+
+ setup_ref(s);
+ for (l = s->cb; l != NULL; l = l->next) {
+ struct a2dp_setup_cb *cb = l->data;
+
+ if (cb->resume_cb) {
+ cb->resume_cb(s->session, s->err, cb->user_data);
+ cb->resume_cb = NULL;
+ setup_unref(s);
+ }
+ }
+
+ setup_unref(s);
+ return FALSE;
+}
+
+static gboolean finalize_resume_errno(struct a2dp_setup *s, int err)
+{
+ struct avdtp_error avdtp_err;
+
+ avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
+ s->err = err ? &avdtp_err : NULL;
+
+ return finalize_resume(s);
+}
+
+static gboolean finalize_suspend(struct a2dp_setup *s)
+{
+ GSList *l;
+
+ setup_ref(s);
+ for (l = s->cb; l != NULL; l = l->next) {
+ struct a2dp_setup_cb *cb = l->data;
+
+ if (cb->suspend_cb) {
+ cb->suspend_cb(s->session, s->err, cb->user_data);
+ cb->suspend_cb = NULL;
+ setup_unref(s);
+ }
+ }
+
+ setup_unref(s);
+ return FALSE;
+}
+
+static gboolean finalize_suspend_errno(struct a2dp_setup *s, int err)
+{
+ struct avdtp_error avdtp_err;
+
+ avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
+ s->err = err ? &avdtp_err : NULL;
+
+ return finalize_suspend(s);
+}
+
+static struct a2dp_setup *find_setup_by_session(struct avdtp *session)
+{
+ GSList *l;
+
+ for (l = setups; l != NULL; l = l->next) {
+ struct a2dp_setup *setup = l->data;
+
+ if (setup->session == session)
+ return setup;
+ }
+
+ return NULL;
+}
+
+static struct a2dp_setup *find_setup_by_dev(struct audio_device *dev)
+{
+ GSList *l;
+
+ for (l = setups; l != NULL; l = l->next) {
+ struct a2dp_setup *setup = l->data;
+ struct audio_device *setup_dev = a2dp_get_dev(setup->session);
+
+ if (setup_dev == dev)
+ return setup;
+ }
+
+ return NULL;
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+ avdtp_state_t old_state,
+ avdtp_state_t new_state,
+ struct avdtp_error *err,
+ void *user_data)
+{
+ struct a2dp_sep *sep = user_data;
+
+ if (new_state != AVDTP_STATE_IDLE)
+ return;
+
+ if (sep->suspend_timer) {
+ g_source_remove(sep->suspend_timer);
+ sep->suspend_timer = 0;
+ }
+
+ if (sep->session) {
+ avdtp_unref(sep->session);
+ sep->session = NULL;
+ }
+
+ sep->stream = NULL;
+
+}
+
+static gboolean sbc_setconf_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ GSList *caps, uint8_t *err,
+ uint8_t *category, void *user_data)
+{
+ 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);
+ else
+ debug("Source %p: Set_Configuration_Ind", sep);
+
+ dev = a2dp_get_dev(session);
+ if (!dev) {
+ *err = AVDTP_UNSUPPORTED_CONFIGURATION;
+ *category = 0x00;
+ return FALSE;
+ }
+
+ /* Check bipool range */
+ for (codec_cap = NULL; caps; caps = g_slist_next(caps)) {
+ cap = caps->data;
+ if (cap->category == AVDTP_MEDIA_CODEC) {
+ codec_cap = (void *) cap->data;
+ if (codec_cap->media_codec_type == A2DP_CODEC_SBC) {
+ sbc_cap = (void *) codec_cap;
+ if (sbc_cap->min_bitpool < MIN_BITPOOL ||
+ sbc_cap->max_bitpool > MAX_BITPOOL) {
+ *err = AVDTP_UNSUPPORTED_CONFIGURATION;
+ *category = AVDTP_MEDIA_CODEC;
+ return FALSE;
+ }
+ }
+ break;
+ }
+ }
+
+ avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
+ a2dp_sep->stream = stream;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)
+ sink_new_stream(dev, session, stream);
+
+ return TRUE;
+}
+
+static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ 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);
+ else
+ debug("Source %p: Get_Capability_Ind", sep);
+
+ *caps = NULL;
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ *caps = g_slist_append(*caps, media_transport);
+
+ memset(&sbc_cap, 0, sizeof(struct sbc_codec_cap));
+
+ sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
+
+ sbc_cap.frequency = ( SBC_SAMPLING_FREQ_48000 |
+ SBC_SAMPLING_FREQ_44100 |
+ SBC_SAMPLING_FREQ_32000 |
+ SBC_SAMPLING_FREQ_16000 );
+
+ sbc_cap.channel_mode = ( SBC_CHANNEL_MODE_JOINT_STEREO |
+ SBC_CHANNEL_MODE_STEREO |
+ SBC_CHANNEL_MODE_DUAL_CHANNEL |
+ SBC_CHANNEL_MODE_MONO );
+
+ sbc_cap.block_length = ( SBC_BLOCK_LENGTH_16 |
+ SBC_BLOCK_LENGTH_12 |
+ SBC_BLOCK_LENGTH_8 |
+ SBC_BLOCK_LENGTH_4 );
+
+ sbc_cap.subbands = ( SBC_SUBBANDS_8 | SBC_SUBBANDS_4 );
+
+ sbc_cap.allocation_method = ( SBC_ALLOCATION_LOUDNESS |
+ SBC_ALLOCATION_SNR );
+
+ sbc_cap.min_bitpool = MIN_BITPOOL;
+ sbc_cap.max_bitpool = MAX_BITPOOL;
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
+ sizeof(sbc_cap));
+
+ *caps = g_slist_append(*caps, media_codec);
+
+ return TRUE;
+}
+
+static gboolean mpeg_setconf_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ GSList *caps, uint8_t *err,
+ uint8_t *category, void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+ struct audio_device *dev;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Set_Configuration_Ind", sep);
+ else
+ debug("Source %p: Set_Configuration_Ind", sep);
+
+ dev = a2dp_get_dev(session);
+ if (!dev) {
+ *err = AVDTP_UNSUPPORTED_CONFIGURATION;
+ *category = 0x00;
+ return FALSE;
+ }
+
+ avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
+ a2dp_sep->stream = stream;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)
+ sink_new_stream(dev, session, stream);
+
+ return TRUE;
+}
+
+static gboolean mpeg_getcap_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ GSList **caps, uint8_t *err, void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+ struct avdtp_service_capability *media_transport, *media_codec;
+ struct mpeg_codec_cap mpeg_cap;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Get_Capability_Ind", sep);
+ else
+ debug("Source %p: Get_Capability_Ind", sep);
+
+ *caps = NULL;
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ *caps = g_slist_append(*caps, media_transport);
+
+ memset(&mpeg_cap, 0, sizeof(struct mpeg_codec_cap));
+
+ mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
+
+ mpeg_cap.frequency = ( MPEG_SAMPLING_FREQ_48000 |
+ MPEG_SAMPLING_FREQ_44100 |
+ MPEG_SAMPLING_FREQ_32000 |
+ MPEG_SAMPLING_FREQ_24000 |
+ MPEG_SAMPLING_FREQ_22050 |
+ MPEG_SAMPLING_FREQ_16000 );
+
+ mpeg_cap.channel_mode = ( MPEG_CHANNEL_MODE_JOINT_STEREO |
+ MPEG_CHANNEL_MODE_STEREO |
+ MPEG_CHANNEL_MODE_DUAL_CHANNEL |
+ MPEG_CHANNEL_MODE_MONO );
+
+ mpeg_cap.layer = ( MPEG_LAYER_MP3 | MPEG_LAYER_MP2 | MPEG_LAYER_MP1 );
+
+ mpeg_cap.bitrate = 0xFFFF;
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
+ sizeof(mpeg_cap));
+
+ *caps = g_slist_append(*caps, media_codec);
+
+ return TRUE;
+}
+
+static void setconf_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;
+ struct a2dp_setup *setup;
+ struct audio_device *dev;
+ int ret;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Set_Configuration_Cfm", sep);
+ else
+ debug("Source %p: Set_Configuration_Cfm", sep);
+
+ setup = find_setup_by_session(session);
+
+ if (err) {
+ if (setup) {
+ setup->err = err;
+ finalize_config(setup);
+ }
+ return;
+ }
+
+ avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
+ a2dp_sep->stream = stream;
+
+ if (!setup)
+ return;
+
+ dev = a2dp_get_dev(session);
+
+ /* Notify sink.c of the new stream */
+ sink_new_stream(dev, session, setup->stream);
+
+ ret = avdtp_open(session, stream);
+ if (ret < 0) {
+ error("Error on avdtp_open %s (%d)", strerror(-ret),
+ -ret);
+ setup->stream = NULL;
+ finalize_config_errno(setup, ret);
+ }
+}
+
+static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ uint8_t *err, void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Get_Configuration_Ind");
+ else
+ debug("Source %p: Get_Configuration_Ind");
+ return TRUE;
+}
+
+static void getconf_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)
+ debug("Sink %p: Set_Configuration_Cfm", sep);
+ else
+ debug("Source %p: Set_Configuration_Cfm", sep);
+}
+
+static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Open_Ind", sep);
+ else
+ debug("Source %p: Open_Ind", sep);
+ return TRUE;
+}
+
+static void open_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;
+ struct a2dp_setup *setup;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Open_Cfm", sep);
+ else
+ debug("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;
+
+ if (err) {
+ setup->stream = NULL;
+ setup->err = err;
+ finalize_config(setup);
+ }
+ else
+ finalize_config_errno(setup, 0);
+}
+
+static gboolean suspend_timeout(struct a2dp_sep *sep)
+{
+ if (avdtp_suspend(sep->session, sep->stream) == 0)
+ sep->suspending = TRUE;
+
+ sep->suspend_timer = 0;
+
+ avdtp_unref(sep->session);
+ sep->session = NULL;
+
+ return FALSE;
+}
+
+static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Start_Ind", sep);
+ else
+ debug("Source %p: Start_Ind", sep);
+
+ if (!a2dp_sep->locked) {
+ a2dp_sep->session = avdtp_ref(session);
+ a2dp_sep->suspend_timer = g_timeout_add(SUSPEND_TIMEOUT,
+ (GSourceFunc) suspend_timeout,
+ a2dp_sep);
+ }
+
+ return TRUE;
+}
+
+static void start_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;
+ struct a2dp_setup *setup;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Start_Cfm", sep);
+ else
+ debug("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;
+ finalize_resume(setup);
+ }
+ else
+ finalize_resume_errno(setup, 0);
+}
+
+static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Suspend_Ind", sep);
+ else
+ debug("Source %p: Suspend_Ind", sep);
+
+ if (a2dp_sep->suspend_timer) {
+ g_source_remove(a2dp_sep->suspend_timer);
+ a2dp_sep->suspend_timer = 0;
+ avdtp_unref(a2dp_sep->session);
+ a2dp_sep->session = NULL;
+ }
+
+ return TRUE;
+}
+
+static void suspend_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;
+ struct a2dp_setup *setup;
+ gboolean start;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Suspend_Cfm", sep);
+ else
+ debug("Source %p: Suspend_Cfm", sep);
+
+ a2dp_sep->suspending = FALSE;
+
+ setup = find_setup_by_session(session);
+ if (!setup)
+ return;
+
+ start = setup->start;
+ setup->start = FALSE;
+
+ if (err) {
+ setup->stream = NULL;
+ setup->err = err;
+ finalize_suspend(setup);
+ }
+ else
+ finalize_suspend_errno(setup, 0);
+
+ if (!start)
+ return;
+
+ if (err) {
+ setup->err = err;
+ finalize_suspend(setup);
+ } else if (avdtp_start(session, a2dp_sep->stream) < 0) {
+ struct avdtp_error start_err;
+ error("avdtp_start failed");
+ avdtp_error_init(&start_err, AVDTP_ERROR_ERRNO, EIO);
+ setup->err = err;
+ finalize_suspend(setup);
+ }
+}
+
+static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Close_Ind", sep);
+ else
+ debug("Source %p: Close_Ind", sep);
+
+ return TRUE;
+}
+
+static gboolean a2dp_reconfigure(gpointer data)
+{
+ struct a2dp_setup *setup = data;
+ struct avdtp_local_sep *lsep;
+ struct avdtp_remote_sep *rsep;
+ struct avdtp_service_capability *cap;
+ struct avdtp_media_codec_capability *codec_cap = NULL;
+ GSList *l;
+ int posix_err;
+
+ for (l = setup->client_caps; l != NULL; l = l->next) {
+ cap = l->data;
+
+ if (cap->category != AVDTP_MEDIA_CODEC)
+ continue;
+
+ codec_cap = (void *) cap->data;
+ break;
+ }
+
+ posix_err = avdtp_get_seps(setup->session, AVDTP_SEP_TYPE_SINK,
+ codec_cap->media_type,
+ codec_cap->media_codec_type,
+ &lsep, &rsep);
+ if (posix_err < 0) {
+ error("No matching ACP and INT SEPs found");
+ finalize_config_errno(setup, posix_err);
+ }
+
+ posix_err = avdtp_set_configuration(setup->session, rsep, lsep,
+ setup->client_caps,
+ &setup->stream);
+ if (posix_err < 0) {
+ error("avdtp_set_configuration: %s",
+ strerror(-posix_err));
+ finalize_config_errno(setup, posix_err);
+ }
+
+ return FALSE;
+}
+
+static void close_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;
+ struct a2dp_setup *setup;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Close_Cfm", sep);
+ else
+ debug("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;
+ finalize_config(setup);
+ return;
+ }
+
+ if (setup->reconfigure)
+ g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup);
+}
+
+static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Abort_Ind", sep);
+ else
+ debug("Source %p: Abort_Ind", sep);
+
+ a2dp_sep->stream = NULL;
+
+ return TRUE;
+}
+
+static void abort_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;
+ struct a2dp_setup *setup;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: Abort_Cfm", sep);
+ else
+ debug("Source %p: Abort_Cfm", sep);
+
+ setup = find_setup_by_session(session);
+ if (!setup)
+ return;
+
+ setup_unref(setup);
+}
+
+static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+ uint8_t *err, void *user_data)
+{
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: ReConfigure_Ind", sep);
+ else
+ debug("Source %p: ReConfigure_Ind", sep);
+ return TRUE;
+}
+
+static void reconf_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;
+ struct a2dp_setup *setup;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+ debug("Sink %p: ReConfigure_Cfm", sep);
+ else
+ debug("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;
+ finalize_config(setup);
+ }
+ else
+ finalize_config_errno(setup, 0);
+}
+
+static struct avdtp_sep_cfm cfm = {
+ .set_configuration = setconf_cfm,
+ .get_configuration = getconf_cfm,
+ .open = open_cfm,
+ .start = start_cfm,
+ .suspend = suspend_cfm,
+ .close = close_cfm,
+ .abort = abort_cfm,
+ .reconfigure = reconf_cfm
+};
+
+static struct avdtp_sep_ind sbc_ind = {
+ .get_capability = sbc_getcap_ind,
+ .set_configuration = sbc_setconf_ind,
+ .get_configuration = getconf_ind,
+ .open = open_ind,
+ .start = start_ind,
+ .suspend = suspend_ind,
+ .close = close_ind,
+ .abort = abort_ind,
+ .reconfigure = reconf_ind
+};
+
+static struct avdtp_sep_ind mpeg_ind = {
+ .get_capability = mpeg_getcap_ind,
+ .set_configuration = mpeg_setconf_ind,
+ .get_configuration = getconf_ind,
+ .open = open_ind,
+ .start = start_ind,
+ .suspend = suspend_ind,
+ .close = close_ind,
+ .abort = abort_ind,
+ .reconfigure = reconf_ind
+};
+
+static sdp_record_t *a2dp_source_record()
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, avdtp, a2src;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *psm, *version, *features;
+ uint16_t lp = AVDTP_UUID, ver = 0x0100, feat = 0x000F;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &a2src);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&avdtp, AVDTP_UUID);
+ proto[1] = sdp_list_append(0, &avdtp);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ features = sdp_data_alloc(SDP_UINT16, &feat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ sdp_set_info_attr(record, "Audio Source", 0, 0);
+
+ free(psm);
+ free(version);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static sdp_record_t *a2dp_sink_record()
+{
+ return NULL;
+}
+
+static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,
+ uint8_t codec)
+{
+ struct a2dp_sep *sep;
+ GSList **l;
+ sdp_record_t *(*create_record)(void);
+ uint32_t *record_id;
+ sdp_record_t *record;
+ struct avdtp_sep_ind *ind;
+
+ sep = g_new0(struct a2dp_sep, 1);
+
+ ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
+ sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO, codec,
+ ind, &cfm, sep);
+ if (sep->sep == NULL) {
+ g_free(sep);
+ return NULL;
+ }
+
+ sep->codec = codec;
+ sep->type = type;
+
+ if (type == AVDTP_SEP_TYPE_SOURCE) {
+ l = &sources;
+ create_record = a2dp_source_record;
+ record_id = &source_record_id;
+ } else {
+ l = &sinks;
+ create_record = a2dp_sink_record;
+ record_id = &sink_record_id;
+ }
+
+ if (*record_id != 0)
+ goto add;
+
+ record = create_record();
+ if (!record) {
+ error("Unable to allocate new service record");
+ avdtp_unregister_sep(sep->sep);
+ g_free(sep);
+ return NULL;
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ error("Unable to register A2DP service record");\
+ sdp_record_free(record);
+ avdtp_unregister_sep(sep->sep);
+ g_free(sep);
+ return NULL;
+ }
+ *record_id = record->handle;
+
+add:
+ *l = g_slist_append(*l, sep);
+
+ return sep;
+}
+
+int a2dp_init(DBusConnection *conn, GKeyFile *config)
+{
+ int sbc_srcs = 1, sbc_sinks = 0;
+ int mpeg12_srcs = 0, mpeg12_sinks = 0;
+ gboolean source = TRUE, sink = TRUE;
+ char *str;
+ GError *err = NULL;
+ int i;
+
+ if (!config)
+ goto proceed;
+
+ str = g_key_file_get_string(config, "General", "Disable", &err);
+
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ if (strstr(str, "Sink"))
+ source = FALSE;
+ if (strstr(str, "Source"))
+ sink = FALSE;
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ sbc_srcs = atoi(str);
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ mpeg12_srcs = atoi(str);
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ sbc_sinks = atoi(str);
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ mpeg12_sinks = atoi(str);
+ g_free(str);
+ }
+
+proceed:
+ connection = dbus_connection_ref(conn);
+
+ avdtp_init(config);
+
+ if (source) {
+ for (i = 0; i < sbc_srcs; i++)
+ a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE,
+ A2DP_CODEC_SBC);
+
+ for (i = 0; i < mpeg12_srcs; i++)
+ a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE,
+ A2DP_CODEC_MPEG12);
+ }
+
+ if (sink) {
+ for (i = 0; i < sbc_sinks; i++)
+ a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK,
+ A2DP_CODEC_SBC);
+
+ for (i = 0; i < mpeg12_sinks; i++)
+ a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK,
+ A2DP_CODEC_MPEG12);
+ }
+
+ return 0;
+}
+
+static void a2dp_unregister_sep(struct a2dp_sep *sep)
+{
+ avdtp_unregister_sep(sep->sep);
+ g_free(sep);
+}
+
+void a2dp_exit()
+{
+ g_slist_foreach(sinks, (GFunc) a2dp_unregister_sep, NULL);
+ g_slist_free(sinks);
+ sinks = NULL;
+
+ g_slist_foreach(sources, (GFunc) a2dp_unregister_sep, NULL);
+ g_slist_free(sources);
+ sources = NULL;
+
+ if (source_record_id) {
+ remove_record_from_server(source_record_id);
+ source_record_id = 0;
+ }
+
+ if (sink_record_id) {
+ remove_record_from_server(sink_record_id);
+ sink_record_id = 0;
+ }
+
+ dbus_connection_unref(connection);
+}
+
+gboolean a2dp_source_cancel(struct audio_device *dev, unsigned int id)
+{
+ struct a2dp_setup_cb *cb_data;
+ struct a2dp_setup *setup;
+ GSList *l;
+
+ setup = find_setup_by_dev(dev);
+ if (!setup)
+ return FALSE;
+
+ for (cb_data = NULL, l = setup->cb; l != NULL; l = g_slist_next(l)) {
+ struct a2dp_setup_cb *cb = l->data;
+
+ if (cb->id == id) {
+ cb_data = cb;
+ break;
+ }
+ }
+
+ if (!cb_data)
+ return FALSE;
+
+ setup->cb = g_slist_remove(setup->cb, cb_data);
+ g_free(cb_data);
+
+ if (!setup->cb) {
+ setup->canceled = TRUE;
+ setup->sep = NULL;
+ }
+
+ return TRUE;
+}
+
+unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
+ GSList *caps, void *user_data)
+{
+ struct a2dp_setup_cb *cb_data;
+ GSList *l;
+ struct a2dp_setup *setup;
+ struct a2dp_sep *sep = NULL, *tmp;
+ struct avdtp_local_sep *lsep;
+ struct avdtp_remote_sep *rsep;
+ struct avdtp_service_capability *cap;
+ struct avdtp_media_codec_capability *codec_cap = NULL;
+ int posix_err;
+
+ for (l = caps; l != NULL; l = l->next) {
+ cap = l->data;
+
+ if (cap->category != AVDTP_MEDIA_CODEC)
+ continue;
+
+ codec_cap = (void *) cap->data;
+ break;
+ }
+
+ if (!codec_cap)
+ return 0;
+
+ for (l = sources; l != NULL; l = l->next) {
+ tmp = l->data;
+
+ if (tmp->locked)
+ continue;
+
+ if (tmp->codec != codec_cap->media_codec_type)
+ continue;
+
+ if (!tmp->stream || avdtp_has_stream(session, tmp->stream)) {
+ sep = tmp;
+ break;
+ }
+ }
+
+ if (!sep) {
+ error("a2dp_source_cfg: no available SEP found");
+ return 0;
+ }
+
+ debug("a2dp_source_config: selected SEP %p", sep->sep);
+
+ cb_data = g_new0(struct a2dp_setup_cb, 1);
+ cb_data->config_cb = cb;
+ cb_data->user_data = user_data;
+ cb_data->id = ++cb_id;
+
+ setup = find_setup_by_session(session);
+ if (!setup) {
+ setup = g_new0(struct a2dp_setup, 1);
+ setup->session = avdtp_ref(session);
+ setups = g_slist_append(setups, setup);
+ }
+
+ setup_ref(setup);
+ setup->cb = g_slist_append(setup->cb, cb_data);
+ setup->sep = sep;
+ setup->stream = sep->stream;
+ setup->client_caps = caps;
+
+ switch (avdtp_sep_get_state(sep->sep)) {
+ case AVDTP_STATE_IDLE:
+ for (l = sources; l != NULL; l = l->next) {
+ tmp = l->data;
+
+ if (avdtp_has_stream(session, tmp->stream))
+ break;
+ }
+
+ if (l != NULL) {
+ setup->reconfigure = TRUE;
+ if (avdtp_close(session, tmp->stream) < 0) {
+ error("avdtp_close failed");
+ goto failed;
+ }
+ break;
+ }
+
+ if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK,
+ codec_cap->media_type,
+ codec_cap->media_codec_type,
+ &lsep, &rsep) < 0) {
+ error("No matching ACP and INT SEPs found");
+ goto failed;
+ }
+
+ posix_err = avdtp_set_configuration(session, rsep, lsep,
+ caps, &setup->stream);
+ if (posix_err < 0) {
+ error("avdtp_set_configuration: %s",
+ strerror(-posix_err));
+ goto failed;
+ }
+ break;
+ case AVDTP_STATE_OPEN:
+ case AVDTP_STATE_STREAMING:
+ if (avdtp_stream_has_capabilities(setup->stream, caps))
+ g_idle_add((GSourceFunc) finalize_config, setup);
+ else if (!setup->reconfigure) {
+ setup->reconfigure = TRUE;
+ if (avdtp_close(session, sep->stream) < 0) {
+ error("avdtp_close failed");
+ goto failed;
+ }
+ }
+ break;
+ default:
+ error("SEP in bad state for requesting a new stream");
+ goto failed;
+ }
+
+ return cb_data->id;
+
+failed:
+ setup_unref(setup);
+ cb_id--;
+ return 0;
+}
+
+unsigned int a2dp_source_resume(struct avdtp *session, struct a2dp_sep *sep,
+ a2dp_stream_cb_t cb, void *user_data)
+{
+ struct a2dp_setup_cb *cb_data;
+ struct a2dp_setup *setup;
+
+ cb_data = g_new0(struct a2dp_setup_cb, 1);
+ cb_data->resume_cb = cb;
+ cb_data->user_data = user_data;
+ cb_data->id = ++cb_id;
+
+ setup = find_setup_by_session(session);
+ if (!setup) {
+ setup = g_new0(struct a2dp_setup, 1);
+ setup->session = avdtp_ref(session);
+ setups = g_slist_append(setups, setup);
+ }
+
+ setup_ref(setup);
+ setup->cb = g_slist_append(setup->cb, cb_data);
+ setup->sep = sep;
+ setup->stream = sep->stream;
+
+ switch (avdtp_sep_get_state(sep->sep)) {
+ case AVDTP_STATE_IDLE:
+ goto failed;
+ break;
+ case AVDTP_STATE_OPEN:
+ if (avdtp_start(session, sep->stream) < 0) {
+ error("avdtp_start failed");
+ goto failed;
+ }
+ break;
+ case AVDTP_STATE_STREAMING:
+ if (!sep->suspending && sep->suspend_timer) {
+ g_source_remove(sep->suspend_timer);
+ sep->suspend_timer = 0;
+ avdtp_unref(sep->session);
+ sep->session = NULL;
+ }
+ if (sep->suspending)
+ setup->start = TRUE;
+ else
+ g_idle_add((GSourceFunc) finalize_resume, setup);
+ break;
+ default:
+ error("SEP in bad state");
+ goto failed;
+ }
+
+ return cb_data->id;
+
+failed:
+ setup_unref(setup);
+ cb_id--;
+ return 0;
+}
+
+unsigned int a2dp_source_suspend(struct avdtp *session, struct a2dp_sep *sep,
+ a2dp_stream_cb_t cb, void *user_data)
+{
+ struct a2dp_setup_cb *cb_data;
+ struct a2dp_setup *setup;
+
+ cb_data = g_new0(struct a2dp_setup_cb, 1);
+ cb_data->suspend_cb = cb;
+ cb_data->user_data = user_data;
+ cb_data->id = ++cb_id;
+
+ setup = find_setup_by_session(session);
+ if (!setup) {
+ setup = g_new0(struct a2dp_setup, 1);
+ setup->session = avdtp_ref(session);
+ setups = g_slist_append(setups, setup);
+ }
+
+ setup_ref(setup);
+ setup->cb = g_slist_append(setup->cb, cb_data);
+ setup->sep = sep;
+ setup->stream = sep->stream;
+
+ switch (avdtp_sep_get_state(sep->sep)) {
+ case AVDTP_STATE_IDLE:
+ error("a2dp_source_suspend: no stream to suspend");
+ goto failed;
+ break;
+ case AVDTP_STATE_OPEN:
+ g_idle_add((GSourceFunc) finalize_suspend, setup);
+ break;
+ case AVDTP_STATE_STREAMING:
+ if (avdtp_suspend(session, sep->stream) < 0) {
+ error("avdtp_suspend failed");
+ goto failed;
+ }
+ break;
+ default:
+ error("SEP in bad state for resume");
+ goto failed;
+ }
+
+ return cb_data->id;
+
+failed:
+ setup_unref(setup);
+ cb_id--;
+ return 0;
+}
+
+gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session)
+{
+ if (sep->locked)
+ return FALSE;
+
+ debug("SEP %p locked", sep->sep);
+ sep->locked = TRUE;
+
+ return TRUE;
+}
+
+gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session)
+{
+ avdtp_state_t state;
+
+ state = avdtp_sep_get_state(sep->sep);
+
+ sep->locked = FALSE;
+
+ debug("SEP %p unlocked", sep->sep);
+
+ if (!sep->stream || state == AVDTP_STATE_IDLE)
+ return TRUE;
+
+ switch (state) {
+ case AVDTP_STATE_OPEN:
+ /* Set timer here */
+ break;
+ case AVDTP_STATE_STREAMING:
+ if (avdtp_suspend(session, sep->stream) == 0)
+ sep->suspending = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
diff --git a/utils/audio/a2dp.h b/utils/audio/a2dp.h
new file mode 100644
index 00000000..6ec3ebc8
--- /dev/null
+++ b/utils/audio/a2dp.h
@@ -0,0 +1,144 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define A2DP_CODEC_SBC 0x00
+#define A2DP_CODEC_MPEG12 0x01
+#define A2DP_CODEC_MPEG24 0x02
+#define A2DP_CODEC_ATRAC 0x03
+
+#define SBC_SAMPLING_FREQ_16000 (1 << 3)
+#define SBC_SAMPLING_FREQ_32000 (1 << 2)
+#define SBC_SAMPLING_FREQ_44100 (1 << 1)
+#define SBC_SAMPLING_FREQ_48000 1
+
+#define SBC_CHANNEL_MODE_MONO (1 << 3)
+#define SBC_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define SBC_CHANNEL_MODE_STEREO (1 << 1)
+#define SBC_CHANNEL_MODE_JOINT_STEREO 1
+
+#define SBC_BLOCK_LENGTH_4 (1 << 3)
+#define SBC_BLOCK_LENGTH_8 (1 << 2)
+#define SBC_BLOCK_LENGTH_12 (1 << 1)
+#define SBC_BLOCK_LENGTH_16 1
+
+#define SBC_SUBBANDS_4 (1 << 1)
+#define SBC_SUBBANDS_8 1
+
+#define SBC_ALLOCATION_SNR (1 << 1)
+#define SBC_ALLOCATION_LOUDNESS 1
+
+#define MPEG_CHANNEL_MODE_MONO (1 << 3)
+#define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define MPEG_CHANNEL_MODE_STEREO (1 << 1)
+#define MPEG_CHANNEL_MODE_JOINT_STEREO 1
+
+#define MPEG_LAYER_MP1 (1 << 2)
+#define MPEG_LAYER_MP2 (1 << 1)
+#define MPEG_LAYER_MP3 1
+
+#define MPEG_SAMPLING_FREQ_16000 (1 << 5)
+#define MPEG_SAMPLING_FREQ_22050 (1 << 4)
+#define MPEG_SAMPLING_FREQ_24000 (1 << 3)
+#define MPEG_SAMPLING_FREQ_32000 (1 << 2)
+#define MPEG_SAMPLING_FREQ_44100 (1 << 1)
+#define MPEG_SAMPLING_FREQ_48000 1
+
+#define MAX_BITPOOL 64
+#define MIN_BITPOOL 2
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct sbc_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t channel_mode:4;
+ uint8_t frequency:4;
+ uint8_t allocation_method:2;
+ uint8_t subbands:2;
+ uint8_t block_length:4;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+struct mpeg_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t channel_mode:4;
+ uint8_t crc:1;
+ uint8_t layer:3;
+ uint8_t frequency:6;
+ uint8_t mpf:1;
+ uint8_t rfa:1;
+ uint16_t bitrate;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct sbc_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t frequency:4;
+ uint8_t channel_mode:4;
+ uint8_t block_length:4;
+ uint8_t subbands:2;
+ uint8_t allocation_method:2;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+struct mpeg_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t layer:3;
+ uint8_t crc:1;
+ uint8_t channel_mode:4;
+ uint8_t rfa:1;
+ uint8_t mpf:1;
+ uint8_t frequency:6;
+ uint16_t bitrate;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct a2dp_sep;
+
+typedef void (*a2dp_config_cb_t) (struct avdtp *session, struct a2dp_sep *sep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data);
+typedef void (*a2dp_stream_cb_t) (struct avdtp *session,
+ struct avdtp_error *err,
+ void *user_data);
+
+int a2dp_init(DBusConnection *conn, GKeyFile *config);
+void a2dp_exit(void);
+
+unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
+ GSList *caps, void *user_data);
+unsigned int a2dp_source_resume(struct avdtp *session, struct a2dp_sep *sep,
+ a2dp_stream_cb_t cb, void *user_data);
+unsigned int a2dp_source_suspend(struct avdtp *session, struct a2dp_sep *sep,
+ a2dp_stream_cb_t cb, void *user_data);
+gboolean a2dp_source_cancel(struct audio_device *dev, unsigned int id);
+
+gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session);
+gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session);
diff --git a/utils/audio/asound.conf b/utils/audio/asound.conf
new file mode 100644
index 00000000..ec97d46f
--- /dev/null
+++ b/utils/audio/asound.conf
@@ -0,0 +1,7 @@
+pcm.headset {
+ type bluetooth
+}
+
+ctl.headset {
+ type bluetooth
+}
diff --git a/utils/audio/audio-api.txt b/utils/audio/audio-api.txt
new file mode 100644
index 00000000..cba20699
--- /dev/null
+++ b/utils/audio/audio-api.txt
@@ -0,0 +1,311 @@
+Bluetooth audio service API description
+***************************************
+
+Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com>
+Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+
+
+org.bluez.audio.Manager interface
+=================================
+
+This interface is for managing remote audio devices. It provides methods for
+creating and removing D-Bus objects representing remote audio devices. These
+objects implement one or more of the other interfaces listed in this document.
+
+Object path /org/bluez/audio
+
+Methods
+ string CreateDevice(string address) [experimental]
+
+ Creates a new audio device object. If not yet done,
+ this method will perform a SDP query on the remote
+ device and return first when the query is complete,
+ so be sure to call this method asynchronously.
+
+ The return parameter is the object path of the newly
+ created object.
+
+ void RemoveDevice(string path) [experimental]
+
+ Removes a device from the device tree. If there are
+ any connections open to the device they will be closed.
+
+ array{string} ListDevices() [experimental]
+
+ Retuns an array of strings indicating the object paths
+ of available devices.
+
+ string DefaultDevice()
+
+ Returns the object path for the default device.
+
+ void ChangeDefaultDevice(string path)
+
+ Changes the default device.
+
+ array{string} ListHeadsets()
+
+ Returns list of headset objects that are configured.
+
+ string FindDeviceByAddress(string address) [experimental]
+
+ Searches the list of available devices and returns the
+ object path of the first device which matchess address.
+ If no device is found returns a DoesNotExist error.
+
+ string DefaultHeadset()
+
+ Returns the object path for the default headset device.
+
+ void ChangeDefaultHeadset(string path)
+
+ Changes the default headset.
+
+ string CreateHeadset(string address)
+
+ Create a new headset device and returns its object path
+ on return.
+
+ void RemoveHeadset(string path)
+
+ Removes a headset object and all information
+ related to it.
+
+Signals
+ void DeviceCreated(string path) [experimental]
+
+ Sent when a new device object has been created.
+
+ void DeviceRemoved(string path) [experimental]
+
+ Sent when a device object has been removed.
+
+ void HeadsetCreated(string path)
+
+ Sent when a new headset object has been created.
+
+ void HeadsetRemoved(string path)
+
+ Sent when a headset object has been removed.
+
+ void DefaultHeadsetChanged(string path)
+
+ Sent when the default headset has changed.
+
+
+org.bluez.audio.Device interface
+================================
+
+This interface is implemented by all remote device objects.
+
+Object path(s) /org/bluez/audio/device*
+
+Methods string GetAddress() [experimental]
+
+ Returns the Bluetooth address of the remote device.
+
+ string GetAdapter() [experimental]
+
+ Returns the address of the local adapter that the
+ device is associated with.
+
+ string GetName() [experimental]
+
+ Returns a friendly name for the device.
+
+ array{string} GetConnectedInterfaces() [experimental]
+
+ Returns a string list of interfaces that are in a
+ connected state.
+
+
+org.bluez.audio.Headset interface
+=================================
+
+This interface provides access to headsets that implement the HSP and/or HFP
+profiles.
+
+Object path(s) /org/bluez/audio/device*
+
+Methods void Connect()
+
+ Connect to the HSP/HFP service on the remote device.
+
+ void Disconnect()
+
+ Disconnect from the HSP/HFP service on the remote
+ device.
+
+ boolean IsConnected()
+
+ Returns TRUE if there is a active connection to the
+ HSP/HFP connection on the remote device.
+
+ void IndicateCall()
+
+ Indicate an incoming call on the headset
+ connected to the stream. Will continue to
+ ring the headset about every 3 seconds.
+
+ void CancelCall()
+
+ Cancel the incoming call indication.
+
+ void Play()
+
+ Open the audio connection to the headset.
+
+ void Stop()
+
+ Close the audio connection.
+
+ boolean IsPlaying()
+
+ Returns true if an audio connection to the headset
+ is active.
+
+ uint16 GetSpeakerGain()
+
+ Returns the current speaker gain if available,
+ otherwise returns the error NotAvailable.
+
+ uint16 GetMicrophoneGain()
+
+ Returns the current microphone gain if available,
+ otherwise returns the error NotAvailable.
+
+ void SetSpeakerGain(uint16 gain)
+
+ Changes the current speaker gain if possible.
+
+ void SetMicrophoneGain(uint16 gain)
+
+ Changes the current speaker gain if possible.
+
+ void SetupCall(string value) [experimental]
+
+ Sets up an call with the connected HFP. The value can
+ be "incoming", "outgoing" or "remote" to indicate
+ incoming call, outgoing call and remote party alerted
+ respectively.
+
+ void IdentifyCall(string phone_number, int32 type) [experimental]
+
+ Enables a called subscriber to get the calling
+ line identity (CLI) of the calling party when
+ receiving a call. The value of type shud be
+ the same as provided by the GSM stack.
+
+Signals void AnswerRequested()
+
+ Sent when the answer button is pressed on the headset
+
+ void Connected()
+
+ Sent when the device has been connected to.
+
+ void Disconnected()
+
+ Sent when the device has been disconnected from.
+
+ void Stopped()
+
+ Sent when the audio connection is closed
+
+ void Playing()
+
+ Sent when the audio connection is opened
+
+ void SpeakerGainChanged(uint16 gain)
+
+ The speaker gain changed.
+
+ void MicrophoneGainChanged(uint16 gain)
+
+ The microphone gain changed.
+
+ void CallTerminated()
+
+ Sent when an ongoing call is terminated.
+
+
+org.bluez.audio.Gateway interface
+=================================
+
+[not yet implemented]
+
+This interface is available for remote devices which can function in the Audio
+Gateway role of the HSP and/or HFP profiles.
+
+Object path(s) /org/bluez/audio/device*
+
+
+org.bluez.audio.Sink interface
+==============================
+
+This interface is available for remote devices which contain a A2DP Sink.
+
+Object path(s) /org/bluez/audio/device*
+
+Methods void Connect()
+
+ Connect and setup a stream to a A2DP sink on the
+ remote device.
+
+ void Disconnect()
+
+ Disconnect from the remote device.
+
+ boolean IsConnected()
+
+ Returns TRUE if a stream is setup to a A2DP sink on
+ the remote device.
+
+Signals void Connected()
+
+ Sent when a successful connection has been made to the
+ remote A2DP Sink
+
+ void Disconnected()
+
+ Sent when the device has been disconnected from.
+
+ void Playing()
+
+ Sent when a stream with remote device is started.
+
+ void Stopped()
+
+ Sent when a stream with remote device is suspended.
+
+
+org.bluez.audio.Source interface
+================================
+
+[not yet implemented]
+
+This interface is available for remote devices which implement a A2DP source.
+
+Object path(s) /org/bluez/audio/device*
+
+
+org.bluez.audio.Control interface
+=================================
+
+This interface is available for remote devices which implement support for a
+AVRCP controller.
+
+Object path(s) /org/bluez/audio/device*
+
+Methods boolean IsConnected()
+
+ Returns TRUE if AVRCP is connected.
+
+Signals void Connected()
+
+ Sent when a successful AVRCP connection has been made.
+
+ void Disconnected()
+
+ Sent when the AVRCP connection has been disconnected.
diff --git a/utils/audio/audio.conf b/utils/audio/audio.conf
new file mode 100644
index 00000000..7f760ea6
--- /dev/null
+++ b/utils/audio/audio.conf
@@ -0,0 +1,41 @@
+# Configuration file for the audio service
+
+# This section contains options which are not specific to any
+# particular interface
+[General]
+
+# Switch to master role for incoming connections (defaults to true)
+#Master=true
+
+# If we want to disable support for specific services
+# Defaults to supporting all implemented services
+#Disable=Control,Source
+
+# SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA)
+# Defaults to HCI
+#SCORouting=PCM
+
+# Headset interface specific options (i.e. options which affect how the audio
+# service interacts with remote headset devices)
+[Headset]
+
+# Set to true to support HFP (in addition to HSP only which is the default)
+# Defaults to false
+HFP=false
+
+# HFP Gateway features
+# Defaults to false
+3WayCalling=false
+EchoCancelNoiseCancel=false
+VoiceRecognition=false
+InBandRingtone=false
+VoiceTags=false
+RejectingCalls=false
+EnhancedCallStatus=false
+EnhancedCallControl=false
+ExtendedErrorResultCodes=false
+
+# Just an example of potential config options for the other interfaces
+#[A2DP]
+#SBCSources=1
+#MPEG12Sources=0
diff --git a/utils/audio/avdtp.c b/utils/audio/avdtp.c
new file mode 100644
index 00000000..bda21ac5
--- /dev/null
+++ b/utils/audio/avdtp.c
@@ -0,0 +1,2882 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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 <stdint.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "dbus-service.h"
+#include "logging.h"
+
+#include "device.h"
+#include "manager.h"
+#include "control.h"
+#include "avdtp.h"
+#include "glib-helper.h"
+
+#include <bluetooth/l2cap.h>
+
+#define AVDTP_PSM 25
+
+#define MAX_SEID 0x3E
+
+#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_SECURITY_CONTROL 0x0B
+
+#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_ACCEPT 0x02
+#define AVDTP_MSG_TYPE_REJECT 0x03
+
+#define REQ_TIMEOUT 4000
+#define DISCONNECT_TIMEOUT 5000
+#define STREAM_TIMEOUT 20000
+
+typedef enum {
+ AVDTP_SESSION_STATE_DISCONNECTED,
+ AVDTP_SESSION_STATE_CONNECTING,
+ AVDTP_SESSION_STATE_CONNECTED
+} avdtp_session_state_t;
+
+#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 seid {
+ uint8_t rfa0:2;
+ uint8_t seid:6;
+} __attribute__ ((packed));
+
+#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 seid {
+ uint8_t seid:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+/* packets */
+
+struct gen_req {
+ struct avdtp_header header;
+} __attribute__ ((packed));
+
+struct gen_resp {
+ struct avdtp_header header;
+} __attribute__ ((packed));
+
+struct discover_resp {
+ struct avdtp_header header;
+ struct seid_info seps[0];
+} __attribute__ ((packed));
+
+struct getcap_resp {
+ struct avdtp_header header;
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct start_req {
+ struct avdtp_header header;
+ struct seid first_seid;
+ struct seid other_seids[0];
+} __attribute__ ((packed));
+
+struct suspend_req {
+ struct avdtp_header header;
+ struct seid first_seid;
+ struct seid other_seids[0];
+} __attribute__ ((packed));
+
+struct seid_rej {
+ struct avdtp_header header;
+ uint8_t error;
+} __attribute__ ((packed));
+
+struct conf_rej {
+ struct avdtp_header header;
+ uint8_t category;
+ uint8_t error;
+} __attribute__ ((packed));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct seid_req {
+ struct avdtp_header header;
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+} __attribute__ ((packed));
+
+struct setconf_req {
+ struct avdtp_header header;
+
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+ uint8_t rfa1:2;
+ uint8_t int_seid:6;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct stream_rej {
+ struct avdtp_header header;
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+ uint8_t error;
+} __attribute__ ((packed));
+
+struct reconf_req {
+ struct avdtp_header header;
+
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+
+ uint8_t serv_cap;
+ uint8_t serv_cap_len;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct avdtp_general_rej {
+ uint8_t message_type:2;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+ uint8_t rfa0;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct seid_req {
+ struct avdtp_header header;
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct setconf_req {
+ struct avdtp_header header;
+
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+ uint8_t int_seid:6;
+ uint8_t rfa1:2;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct stream_rej {
+ struct avdtp_header header;
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+ uint8_t error;
+} __attribute__ ((packed));
+
+struct reconf_req {
+ struct avdtp_header header;
+
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+
+ uint8_t serv_cap;
+ uint8_t serv_cap_len;
+
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+struct avdtp_general_rej {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t message_type:2;
+ uint8_t rfa0;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct pending_req {
+ struct avdtp_header *msg;
+ int msg_size;
+ struct avdtp_stream *stream; /* Set if the request targeted a stream */
+ guint timeout;
+};
+
+struct avdtp_remote_sep {
+ uint8_t seid;
+ uint8_t type;
+ uint8_t media_type;
+ struct avdtp_service_capability *codec;
+ GSList *caps; /* of type struct avdtp_service_capability */
+ struct avdtp_stream *stream;
+};
+
+struct avdtp_local_sep {
+ avdtp_state_t state;
+ struct avdtp_stream *stream;
+ struct seid_info info;
+ uint8_t codec;
+ GSList *caps;
+ struct avdtp_sep_ind *ind;
+ struct avdtp_sep_cfm *cfm;
+ void *user_data;
+};
+
+struct stream_callback {
+ avdtp_stream_state_cb cb;
+ void *user_data;
+ unsigned int id;
+};
+
+struct avdtp_stream {
+ int sock;
+ uint16_t imtu;
+ uint16_t omtu;
+ struct avdtp *session;
+ struct avdtp_local_sep *lsep;
+ uint8_t rseid;
+ GSList *caps;
+ GSList *callbacks;
+ struct avdtp_service_capability *codec;
+ guint io; /* Transport GSource ID */
+ guint timer; /* Waiting for other side to close or open
+ the transport channel */
+ gboolean open_acp; /* If we are in ACT role for Open */
+ gboolean close_int; /* If we are in INT role for Close */
+ guint idle_timer;
+};
+
+/* Structure describing an AVDTP connection between two devices */
+struct avdtp {
+ int ref;
+ int free_lock;
+
+ bdaddr_t src;
+ bdaddr_t dst;
+
+ avdtp_session_state_t last_state;
+ avdtp_session_state_t state;
+
+ guint io;
+ int sock;
+
+ GSList *seps; /* Elements of type struct avdtp_remote_sep * */
+
+ GSList *streams; /* Elements of type struct avdtp_stream * */
+
+ GSList *req_queue; /* Elements of type struct pending_req * */
+ GSList *prio_queue; /* Same as req_queue but is processed before it */
+
+ struct avdtp_stream *pending_open;
+
+ uint16_t mtu;
+ char *buf;
+
+ avdtp_discover_cb_t discov_cb;
+ void *user_data;
+
+ struct pending_req *req;
+
+ guint dc_timer;
+
+ DBusPendingCall *pending_auth;
+};
+
+static uint8_t free_seid = 1;
+static GSList *local_seps = NULL;
+
+static GIOChannel *avdtp_server = NULL;
+
+static GSList *sessions = NULL;
+
+static int send_request(struct avdtp *session, gboolean priority,
+ struct avdtp_stream *stream, void *buffer, int size);
+static gboolean avdtp_parse_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_header *header, int size);
+static gboolean avdtp_parse_rej(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_header *header, int size);
+static int process_queue(struct avdtp *session);
+static void connection_lost(struct avdtp *session, int err);
+static void avdtp_sep_set_state(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ avdtp_state_t state);
+
+static const char *avdtp_statestr(avdtp_state_t state)
+{
+ switch (state) {
+ case AVDTP_STATE_IDLE:
+ return "IDLE";
+ case AVDTP_STATE_CONFIGURED:
+ return "CONFIGURED";
+ case AVDTP_STATE_OPEN:
+ return "OPEN";
+ case AVDTP_STATE_STREAMING:
+ return "STREAMING";
+ case AVDTP_STATE_CLOSING:
+ return "CLOSING";
+ case AVDTP_STATE_ABORTING:
+ return "ABORTING";
+ default:
+ return "<unknown state>";
+ }
+}
+
+static gboolean avdtp_send(struct avdtp *session, void *data, int len)
+{
+ int ret;
+
+ if (session->sock < 0) {
+ error("avdtp_send: session is closed");
+ return FALSE;
+ }
+
+ ret = send(session->sock, data, len, 0);
+
+ if (ret < 0)
+ ret = -errno;
+ else if (ret != len)
+ ret = -EIO;
+
+ if (ret < 0) {
+ error("avdtp_send: %s (%d)", strerror(-ret), -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void pending_req_free(struct pending_req *req)
+{
+ if (req->timeout)
+ g_source_remove(req->timeout);
+ g_free(req->msg);
+ g_free(req);
+}
+
+static gboolean stream_close_timeout(gpointer user_data)
+{
+ struct avdtp_stream *stream = user_data;
+
+ debug("Timed out waiting for peer to close the transport channel");
+
+ stream->timer = 0;
+
+ close(stream->sock);
+
+ return FALSE;
+}
+
+static gboolean stream_open_timeout(gpointer user_data)
+{
+ struct avdtp_stream *stream = user_data;
+
+ debug("Timed out waiting for peer to open the transport channel");
+
+ stream->timer = 0;
+
+ stream->session->pending_open = NULL;
+
+ avdtp_abort(stream->session, stream);
+
+ return FALSE;
+}
+
+static gboolean disconnect_timeout(gpointer user_data)
+{
+ struct avdtp *session = user_data;
+
+ assert(session->ref == 1);
+
+ session->dc_timer = 0;
+
+ connection_lost(session, -ETIMEDOUT);
+
+ return FALSE;
+}
+
+static void remove_disconnect_timer(struct avdtp *session)
+{
+ g_source_remove(session->dc_timer);
+ session->dc_timer = 0;
+}
+
+static void set_disconnect_timer(struct avdtp *session)
+{
+ if (session->dc_timer)
+ remove_disconnect_timer(session);
+
+ session->dc_timer = g_timeout_add(DISCONNECT_TIMEOUT,
+ disconnect_timeout, session);
+}
+
+void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id)
+{
+ err->type = type;
+ switch (type) {
+ case AVDTP_ERROR_ERRNO:
+ err->err.posix_errno = id;
+ break;
+ case AVDTP_ERROR_ERROR_CODE:
+ err->err.error_code = id;
+ break;
+ }
+}
+
+avdtp_error_type_t avdtp_error_type(struct avdtp_error *err)
+{
+ return err->type;
+}
+
+int avdtp_error_error_code(struct avdtp_error *err)
+{
+ assert(err->type == AVDTP_ERROR_ERROR_CODE);
+ return err->err.error_code;
+}
+
+int avdtp_error_posix_errno(struct avdtp_error *err)
+{
+ assert(err->type == AVDTP_ERROR_ERRNO);
+ return err->err.posix_errno;
+}
+
+static struct avdtp_stream *find_stream_by_rseid(struct avdtp *session,
+ uint8_t rseid)
+{
+ GSList *l;
+
+ for (l = session->streams; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_stream *stream = l->data;
+
+ if (stream->rseid == rseid)
+ return stream;
+ }
+
+ return NULL;
+}
+
+static struct avdtp_remote_sep *find_remote_sep(GSList *seps, uint8_t seid)
+{
+ GSList *l;
+
+ for (l = seps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_remote_sep *sep = l->data;
+
+ if (sep->seid == seid)
+ return sep;
+ }
+
+ return NULL;
+}
+
+static void stream_free(struct avdtp_stream *stream)
+{
+ struct avdtp_remote_sep *rsep;
+
+ stream->lsep->info.inuse = 0;
+ stream->lsep->stream = NULL;
+
+ rsep = find_remote_sep(stream->session->seps, stream->rseid);
+ if (rsep)
+ rsep->stream = NULL;
+
+ if (stream->timer)
+ g_source_remove(stream->timer);
+
+ if (stream->sock >= 0)
+ close(stream->sock);
+
+ if (stream->io)
+ g_source_remove(stream->io);
+
+ g_slist_foreach(stream->callbacks, (GFunc) g_free, NULL);
+ g_slist_free(stream->callbacks);
+
+ g_slist_foreach(stream->caps, (GFunc) g_free, NULL);
+ g_slist_free(stream->caps);
+
+ g_free(stream);
+}
+
+static gboolean stream_timeout(struct avdtp_stream *stream)
+{
+ struct avdtp *session = stream->session;
+
+ avdtp_close(session, stream);
+
+ stream->idle_timer = 0;
+
+ return FALSE;
+}
+
+static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avdtp_stream *stream = data;
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (stream->close_int && sep->cfm && sep->cfm->close)
+ sep->cfm->close(stream->session, sep, stream, NULL,
+ sep->user_data);
+
+ stream->io = 0;
+
+ avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE);
+
+ return FALSE;
+}
+
+static void handle_transport_connect(struct avdtp *session, int sock,
+ uint16_t imtu, uint16_t omtu)
+{
+ struct avdtp_stream *stream = session->pending_open;
+ struct avdtp_local_sep *sep = stream->lsep;
+ GIOChannel *channel;
+
+ session->pending_open = NULL;
+
+ if (stream->timer) {
+ g_source_remove(stream->timer);
+ stream->timer = 0;
+ }
+
+ if (sock < 0) {
+ if (!stream->open_acp && sep->cfm && sep->cfm->open) {
+ struct avdtp_error err;
+ avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);
+ sep->cfm->open(session, sep, NULL, &err,
+ sep->user_data);
+ }
+ return;
+ }
+
+ stream->sock = sock;
+ stream->omtu = omtu;
+ stream->imtu = imtu;
+
+ if (!stream->open_acp && sep->cfm && sep->cfm->open)
+ sep->cfm->open(session, sep, stream, NULL, sep->user_data);
+
+ channel = g_io_channel_unix_new(stream->sock);
+
+ stream->io = g_io_add_watch(channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) transport_cb, stream);
+ g_io_channel_unref(channel);
+}
+
+static void avdtp_sep_set_state(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ avdtp_state_t state)
+{
+ struct avdtp_stream *stream = sep->stream;
+ avdtp_state_t old_state;
+ struct avdtp_error err, *err_ptr = NULL;
+
+ if (sep->state == state) {
+ avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);
+ debug("stream state change failed: %s", avdtp_strerror(&err));
+ err_ptr = &err;
+ } else {
+ err_ptr = NULL;
+ debug("stream state changed: %s -> %s",
+ avdtp_statestr(sep->state),
+ avdtp_statestr(state));
+ }
+
+ old_state = sep->state;
+ sep->state = state;
+
+ if (stream) {
+ GSList *l;
+ for (l = stream->callbacks; l != NULL; l = g_slist_next(l)) {
+ struct stream_callback *cb = l->data;
+ cb->cb(stream, old_state, state, err_ptr,
+ cb->user_data);
+ }
+ }
+
+ switch (state) {
+ case AVDTP_STATE_OPEN:
+ break;
+ case AVDTP_STATE_STREAMING:
+ case AVDTP_STATE_CLOSING:
+ case AVDTP_STATE_ABORTING:
+ if (stream->idle_timer) {
+ g_source_remove(stream->idle_timer);
+ stream->idle_timer = 0;
+ }
+ break;
+ case AVDTP_STATE_IDLE:
+ if (stream->idle_timer) {
+ g_source_remove(stream->idle_timer);
+ stream->idle_timer = 0;
+ }
+ session->streams = g_slist_remove(session->streams, stream);
+ if (session->pending_open == stream)
+ handle_transport_connect(session, -1, 0, 0);
+ if (session->req && session->req->stream == stream)
+ session->req->stream = NULL;
+ stream_free(stream);
+ if (session->ref == 1 && !session->streams)
+ set_disconnect_timer(session);
+ break;
+ default:
+ break;
+ }
+}
+
+static void finalize_discovery(struct avdtp *session, int err)
+{
+ struct avdtp_error avdtp_err;
+
+ avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
+
+ if (!session->discov_cb)
+ return;
+
+ session->discov_cb(session, session->seps,
+ err ? &avdtp_err : NULL,
+ session->user_data);
+
+ session->discov_cb = NULL;
+ session->user_data = NULL;
+}
+
+static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (sep->cfm && sep->cfm->abort)
+ sep->cfm->abort(session, sep, stream, NULL, sep->user_data);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
+}
+
+static void connection_lost(struct avdtp *session, int err)
+{
+ struct audio_device *dev;
+
+ dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE,
+ FALSE);
+ if (dev)
+ avrcp_disconnect(dev);
+
+ if (session->state == AVDTP_SESSION_STATE_CONNECTED) {
+ char address[18];
+
+ ba2str(&session->dst, address);
+ debug("Disconnected from %s", address);
+ }
+
+ session->free_lock = 1;
+
+ finalize_discovery(session, err);
+
+ g_slist_foreach(session->streams, (GFunc) release_stream, session);
+ session->streams = NULL;
+
+ session->free_lock = 0;
+
+ if (session->sock >= 0) {
+ close(session->sock);
+ session->sock = -1;
+ }
+
+ session->state = AVDTP_SESSION_STATE_DISCONNECTED;
+
+ if (session->io) {
+ g_source_remove(session->io);
+ session->io = 0;
+ }
+
+ if (session->ref != 1)
+ error("connection_lost: ref count not 1 after all callbacks");
+ else
+ avdtp_unref(session);
+}
+
+void avdtp_unref(struct avdtp *session)
+{
+ if (!session)
+ return;
+
+ if (!g_slist_find(sessions, session)) {
+ error("avdtp_unref: trying to unref a unknown session");
+ return;
+ }
+
+ session->ref--;
+
+ debug("avdtp_unref(%p): ref=%d", session, session->ref);
+
+ if (session->ref == 1) {
+ if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
+ close(session->sock);
+ session->sock = -1;
+ }
+
+ if (session->sock >= 0)
+ set_disconnect_timer(session);
+ else if (!session->free_lock) /* Drop the local ref if we
+ aren't connected */
+ session->ref--;
+ }
+
+ if (session->ref > 0)
+ return;
+
+ debug("avdtp_unref(%p): freeing session and removing from list",
+ session);
+
+ if (session->dc_timer)
+ remove_disconnect_timer(session);
+
+ sessions = g_slist_remove(sessions, session);
+
+ if (session->req)
+ pending_req_free(session->req);
+
+ g_slist_foreach(session->seps, (GFunc) g_free, NULL);
+ g_slist_free(session->seps);
+
+ g_free(session->buf);
+
+ g_free(session);
+}
+
+struct avdtp *avdtp_ref(struct avdtp *session)
+{
+ session->ref++;
+ debug("avdtp_ref(%p): ref=%d", session, session->ref);
+ if (session->dc_timer)
+ remove_disconnect_timer(session);
+ return session;
+}
+
+static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid)
+{
+ GSList *l;
+
+ for (l = local_seps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_local_sep *sep = l->data;
+
+ if (sep->info.seid == seid)
+ return sep;
+ }
+
+ return NULL;
+}
+
+static struct avdtp_local_sep *find_local_sep(uint8_t type, uint8_t media_type,
+ uint8_t codec)
+{
+ GSList *l;
+
+ for (l = local_seps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_local_sep *sep = l->data;
+
+ if (sep->info.inuse)
+ continue;
+
+ if (sep->info.type == type &&
+ sep->info.media_type == media_type &&
+ sep->codec == codec)
+ return sep;
+ }
+
+ return NULL;
+}
+
+static GSList *caps_to_list(uint8_t *data, int size,
+ struct avdtp_service_capability **codec)
+{
+ GSList *caps;
+ int processed;
+
+ for (processed = 0, caps = NULL; processed + 2 < size;) {
+ struct avdtp_service_capability *cap;
+ uint8_t length, category;
+
+ category = data[0];
+ length = data[1];
+
+ if (processed + 2 + length > size) {
+ error("Invalid capability data in getcap resp");
+ break;
+ }
+
+ cap = g_malloc(sizeof(struct avdtp_service_capability) +
+ length);
+ memcpy(cap, data, 2 + length);
+
+ processed += 2 + length;
+ data += 2 + length;
+
+ caps = g_slist_append(caps, cap);
+
+ if (category == AVDTP_MEDIA_CODEC &&
+ length >=
+ sizeof(struct avdtp_media_codec_capability))
+ *codec = cap;
+ }
+
+ return caps;
+}
+
+static void init_response(struct avdtp_header *rsp, struct avdtp_header *req,
+ gboolean accept)
+{
+ rsp->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ rsp->message_type = accept ? AVDTP_MSG_TYPE_ACCEPT :
+ AVDTP_MSG_TYPE_REJECT;
+ rsp->transaction = req->transaction;
+ rsp->signal_id = req->signal_id;
+ rsp->rfa0 = 0;
+}
+
+static gboolean avdtp_unknown_cmd(struct avdtp *session,
+ struct avdtp_header *req, int size)
+{
+ struct avdtp_general_rej rej;
+
+ memset(&rej, 0, sizeof(rej));
+
+ rej.packet_type = AVDTP_PKT_TYPE_SINGLE;
+ rej.message_type = AVDTP_MSG_TYPE_REJECT;
+ rej.transaction = req->transaction;
+
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_discover_cmd(struct avdtp *session,
+ struct gen_req *req, int size)
+{
+ GSList *l;
+ struct discover_resp *rsp = (struct discover_resp *) session->buf;
+ struct seid_info *info;
+ int rsp_size;
+
+ init_response(&rsp->header, &req->header, TRUE);
+ rsp_size = sizeof(struct discover_resp);
+ info = rsp->seps;
+
+ for (l = local_seps; l != NULL; l = l->next) {
+ struct avdtp_local_sep *sep = l->data;
+
+ if (rsp_size + sizeof(struct seid_info) > session->mtu)
+ break;
+
+ memcpy(info, &sep->info, sizeof(struct seid_info));
+ rsp_size += sizeof(struct seid_info);
+ info++;
+ }
+
+ return avdtp_send(session, session->buf, rsp_size);
+}
+
+static gboolean avdtp_getcap_cmd(struct avdtp *session,
+ struct seid_req *req, int size)
+{
+ GSList *l, *caps;
+ struct avdtp_local_sep *sep = NULL;
+ struct seid_rej rej;
+ struct getcap_resp *rsp = (struct getcap_resp *) session->buf;
+ int rsp_size;
+ unsigned char *ptr;
+ uint8_t err;
+
+ if (size < sizeof(struct seid_req)) {
+ error("Too short getcap request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(req->acp_seid);
+ if (!sep) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (!sep->ind->get_capability(session, sep, &caps, &err,
+ sep->user_data))
+ goto failed;
+
+ init_response(&rsp->header, &req->header, TRUE);
+ rsp_size = sizeof(struct getcap_resp);
+ ptr = rsp->caps;
+
+ for (l = caps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_service_capability *cap = l->data;
+
+ if (rsp_size + cap->length + 2 > session->mtu)
+ break;
+
+ memcpy(ptr, cap, cap->length + 2);
+ rsp_size += cap->length + 2;
+ ptr += cap->length + 2;
+
+ g_free(cap);
+ }
+
+ g_slist_free(caps);
+
+ return avdtp_send(session, session->buf, rsp_size);
+
+failed:
+ init_response(&rej.header, &req->header, FALSE);
+ rej.error = AVDTP_BAD_ACP_SEID;
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_setconf_cmd(struct avdtp *session,
+ struct setconf_req *req, int size)
+{
+ struct conf_rej rej;
+ struct gen_resp *rsp = (struct gen_resp *) session->buf;
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ uint8_t err, category = 0x00;
+
+ if (size < sizeof(struct setconf_req)) {
+ error("Too short getcap request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(req->acp_seid);
+ if (!sep) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (sep->stream) {
+ err = AVDTP_SEP_IN_USE;
+ goto failed;
+ }
+
+ stream = g_new0(struct avdtp_stream, 1);
+ stream->session = session;
+ stream->lsep = sep;
+ stream->rseid = req->int_seid;
+ stream->caps = caps_to_list(req->caps,
+ size - sizeof(struct setconf_req),
+ &stream->codec);
+ stream->sock = -1;
+
+ if (sep->ind && sep->ind->set_configuration) {
+ if (!sep->ind->set_configuration(session, sep, stream,
+ stream->caps, &err,
+ &category,
+ sep->user_data)) {
+ stream_free(stream);
+ goto failed;
+ }
+ }
+
+ init_response(&rsp->header, &req->header, TRUE);
+
+ if (!avdtp_send(session, rsp, sizeof(struct setconf_req))) {
+ stream_free(stream);
+ return FALSE;
+ }
+
+ sep->stream = stream;
+ session->streams = g_slist_append(session->streams, stream);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+
+ return TRUE;
+
+failed:
+ init_response(&rej.header, &req->header, FALSE);
+ rej.error = err;
+ rej.category = category;
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_getconf_cmd(struct avdtp *session, struct seid_req *req,
+ int size)
+{
+ return avdtp_unknown_cmd(session, (void *) req, size);
+}
+
+static gboolean avdtp_reconf_cmd(struct avdtp *session, struct seid_req *req,
+ int size)
+{
+ return avdtp_unknown_cmd(session, (void *) req, size);
+}
+
+static gboolean avdtp_open_cmd(struct avdtp *session, struct seid_req *req,
+ int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ struct gen_resp *rsp = (struct gen_resp *) session->buf;
+ struct seid_rej rej;
+ uint8_t err;
+
+ if (size < sizeof(struct seid_req)) {
+ error("Too short abort request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(req->acp_seid);
+ if (!sep) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (sep->state != AVDTP_STATE_CONFIGURED) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->ind && sep->ind->open) {
+ if (!sep->ind->open(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ init_response(&rsp->header, &req->header, TRUE);
+
+ if (!avdtp_send(session, rsp, sizeof(struct gen_resp)))
+ return FALSE;
+
+ stream->open_acp = TRUE;
+ session->pending_open = stream;
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+ stream->timer = g_timeout_add(REQ_TIMEOUT, stream_open_timeout,
+ stream);
+
+ return TRUE;
+
+failed:
+ init_response(&rej.header, &req->header, FALSE);
+ rej.error = err;
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_start_cmd(struct avdtp *session, struct start_req *req,
+ int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ struct gen_resp *rsp = (struct gen_resp *) session->buf;
+ struct stream_rej rej;
+ struct seid *seid;
+ uint8_t err, failed_seid;
+ int seid_count, i;
+
+ if (size < sizeof(struct start_req)) {
+ error("Too short start request");
+ return FALSE;
+ }
+
+ seid_count = 1 + size - sizeof(struct start_req);
+
+ seid = &req->first_seid;
+
+ for (i = 0; i < seid_count; i++, seid++) {
+ failed_seid = seid->seid;
+
+ sep = find_local_sep_by_seid(req->first_seid.seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->state != AVDTP_STATE_OPEN) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ if (sep->ind && sep->ind->start) {
+ if (!sep->ind->start(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
+ }
+
+ init_response(&rsp->header, &req->header, TRUE);
+
+ return avdtp_send(session, rsp, sizeof(struct gen_resp));
+
+failed:
+ memset(&rej, 0, sizeof(rej));
+ init_response(&rej.header, &req->header, FALSE);
+ rej.acp_seid = failed_seid;
+ rej.error = err;
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_close_cmd(struct avdtp *session, struct seid_req *req,
+ int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ struct gen_resp *rsp = (struct gen_resp *) session->buf;
+ struct seid_rej rej;
+ uint8_t err;
+
+ if (size < sizeof(struct seid_req)) {
+ error("Too short close request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(req->acp_seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (sep->state != AVDTP_STATE_OPEN &&
+ sep->state != AVDTP_STATE_STREAMING) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->ind && sep->ind->close) {
+ if (!sep->ind->close(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
+
+ init_response(&rsp->header, &req->header, TRUE);
+
+ if (!avdtp_send(session, rsp, sizeof(struct gen_resp)))
+ return FALSE;
+
+ stream->timer = g_timeout_add(REQ_TIMEOUT, stream_close_timeout,
+ stream);
+
+ return TRUE;
+
+failed:
+ init_response(&rej.header, &req->header, FALSE);
+ rej.error = err;
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_suspend_cmd(struct avdtp *session,
+ struct suspend_req *req, int size)
+{
+ struct avdtp_local_sep *sep;
+ struct avdtp_stream *stream;
+ struct gen_resp *rsp = (struct gen_resp *) session->buf;
+ struct stream_rej rej;
+ struct seid *seid;
+ uint8_t err, failed_seid;
+ int seid_count, i;
+
+ if (size < sizeof(struct suspend_req)) {
+ error("Too short suspend request");
+ return FALSE;
+ }
+
+ seid_count = 1 + size - sizeof(struct suspend_req);
+
+ seid = &req->first_seid;
+
+ for (i = 0; i < seid_count; i++, seid++) {
+ failed_seid = seid->seid;
+
+ sep = find_local_sep_by_seid(req->first_seid.seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ stream = sep->stream;
+
+ if (sep->state != AVDTP_STATE_STREAMING) {
+ err = AVDTP_BAD_STATE;
+ goto failed;
+ }
+
+ if (sep->ind && sep->ind->suspend) {
+ if (!sep->ind->suspend(session, sep, stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+ }
+
+ init_response(&rsp->header, &req->header, TRUE);
+
+ return avdtp_send(session, rsp, sizeof(struct gen_resp));
+
+failed:
+ memset(&rej, 0, sizeof(rej));
+ init_response(&rej.header, &req->header, FALSE);
+ rej.acp_seid = failed_seid;
+ rej.error = err;
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_abort_cmd(struct avdtp *session, struct seid_req *req,
+ int size)
+{
+ struct avdtp_local_sep *sep;
+ struct gen_resp *rsp = (struct gen_resp *) session->buf;
+ struct seid_rej rej;
+ uint8_t err;
+ gboolean ret;
+
+ if (size < sizeof(struct seid_req)) {
+ error("Too short abort request");
+ return FALSE;
+ }
+
+ sep = find_local_sep_by_seid(req->acp_seid);
+ if (!sep || !sep->stream) {
+ err = AVDTP_BAD_ACP_SEID;
+ goto failed;
+ }
+
+ if (sep->ind && sep->ind->abort) {
+ if (!sep->ind->abort(session, sep, sep->stream, &err,
+ sep->user_data))
+ goto failed;
+ }
+
+ init_response(&rsp->header, &req->header, TRUE);
+ ret = avdtp_send(session, rsp, sizeof(struct gen_resp));
+
+ if (ret)
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING);
+
+ return ret;
+
+failed:
+ init_response(&rej.header, &req->header, FALSE);
+ rej.error = err;
+ return avdtp_send(session, &rej, sizeof(rej));
+}
+
+static gboolean avdtp_secctl_cmd(struct avdtp *session, struct seid_req *req,
+ int size)
+{
+ return avdtp_unknown_cmd(session, (void *) req, size);
+}
+
+static gboolean avdtp_parse_cmd(struct avdtp *session,
+ struct avdtp_header *header, int size)
+{
+ switch (header->signal_id) {
+ case AVDTP_DISCOVER:
+ debug("Received DISCOVER_CMD");
+ return avdtp_discover_cmd(session, (void *) header, size);
+ case AVDTP_GET_CAPABILITIES:
+ debug("Received GET_CAPABILITIES_CMD");
+ return avdtp_getcap_cmd(session, (void *) header, size);
+ case AVDTP_SET_CONFIGURATION:
+ debug("Received SET_CONFIGURATION_CMD");
+ return avdtp_setconf_cmd(session, (void *) header, size);
+ case AVDTP_GET_CONFIGURATION:
+ debug("Received GET_CONFIGURATION_CMD");
+ return avdtp_getconf_cmd(session, (void *) header, size);
+ case AVDTP_RECONFIGURE:
+ debug("Received RECONFIGURE_CMD");
+ return avdtp_reconf_cmd(session, (void *) header, size);
+ case AVDTP_OPEN:
+ debug("Received OPEN_CMD");
+ return avdtp_open_cmd(session, (void *) header, size);
+ case AVDTP_START:
+ debug("Received START_CMD");
+ return avdtp_start_cmd(session, (void *) header, size);
+ case AVDTP_CLOSE:
+ debug("Received CLOSE_CMD");
+ return avdtp_close_cmd(session, (void *) header, size);
+ case AVDTP_SUSPEND:
+ debug("Received SUSPEND_CMD");
+ return avdtp_suspend_cmd(session, (void *) header, size);
+ case AVDTP_ABORT:
+ debug("Received ABORT_CMD");
+ return avdtp_abort_cmd(session, (void *) header, size);
+ case AVDTP_SECURITY_CONTROL:
+ debug("Received SECURITY_CONTROL_CMD");
+ return avdtp_secctl_cmd(session, (void *) header, size);
+ default:
+ debug("Received unknown request id %u", header->signal_id);
+ return avdtp_unknown_cmd(session, (void *) header, size);
+ }
+}
+
+static void init_request(struct avdtp_header *header, int request_id)
+{
+ static int transaction = 0;
+
+ header->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ header->message_type = AVDTP_MSG_TYPE_COMMAND;
+ header->transaction = transaction;
+ header->signal_id = request_id;
+
+ /* clear rfa bits */
+ header->rfa0 = 0;
+
+ transaction = (transaction + 1) % 16;
+}
+
+static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avdtp *session = data;
+ struct avdtp_header *header;
+ gsize size;
+
+ debug("session_cb");
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ goto failed;
+
+ if (g_io_channel_read(chan, session->buf, session->mtu,
+ &size) != G_IO_ERROR_NONE) {
+ error("IO Channel read error");
+ goto failed;
+ }
+
+ if (size < sizeof(struct avdtp_header)) {
+ error("Received too small packet (%d bytes)", size);
+ goto failed;
+ }
+
+ header = (struct avdtp_header *) session->buf;
+
+ if (header->message_type == AVDTP_MSG_TYPE_COMMAND) {
+ if (!avdtp_parse_cmd(session, header, size)) {
+ error("Unable to handle command. Disconnecting");
+ goto failed;
+ }
+
+ if (session->ref == 1 && !session->streams)
+ set_disconnect_timer(session);
+
+ if (session->streams && session->dc_timer)
+ remove_disconnect_timer(session);
+
+ return TRUE;
+ }
+
+ if (session->req == NULL) {
+ error("No pending request, rejecting message");
+ return TRUE;
+ }
+
+ if (header->transaction != session->req->msg->transaction) {
+ error("Transaction label doesn't match");
+ return TRUE;
+ }
+
+ if (header->signal_id != session->req->msg->signal_id) {
+ error("Reponse signal doesn't match");
+ return TRUE;
+ }
+
+ g_source_remove(session->req->timeout);
+ session->req->timeout = 0;
+
+ switch(header->message_type) {
+ case AVDTP_MSG_TYPE_ACCEPT:
+ if (!avdtp_parse_resp(session, session->req->stream,
+ header, size)) {
+ error("Unable to parse accept response");
+ goto failed;
+ }
+ break;
+ case AVDTP_MSG_TYPE_REJECT:
+ if (!avdtp_parse_rej(session, session->req->stream,
+ header, size)) {
+ error("Unable to parse reject response");
+ goto failed;
+ }
+ break;
+ default:
+ error("Unknown message type");
+ break;
+ }
+
+ pending_req_free(session->req);
+ session->req = NULL;
+
+ process_queue(session);
+
+ return TRUE;
+
+failed:
+ connection_lost(session, -EIO);
+
+ return FALSE;
+}
+
+static void l2cap_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct avdtp *session = user_data;
+ struct l2cap_options l2o;
+ socklen_t len;
+ int sk;
+ char address[18];
+
+ if (!g_slist_find(sessions, session)) {
+ debug("l2cap_connect_cb: session got removed");
+ return;
+ }
+
+ if (err < 0) {
+ error("connect(): %s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ if (session->state == AVDTP_SESSION_STATE_DISCONNECTED) {
+ session->sock = sk;
+ session->state = AVDTP_SESSION_STATE_CONNECTING;
+ }
+
+ ba2str(&session->dst, address);
+ debug("AVDTP: connected %s channel to %s",
+ session->pending_open ? "transport" : "signaling",
+ address);
+
+ memset(&l2o, 0, sizeof(l2o));
+ len = sizeof(l2o);
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
+ &len) < 0) {
+ err = errno;
+ error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err),
+ err);
+ goto failed;
+ }
+
+ if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
+ struct audio_device *dev;
+
+ session->mtu = l2o.imtu;
+ session->buf = g_malloc0(session->mtu);
+ session->state = AVDTP_SESSION_STATE_CONNECTED;
+ session->io = g_io_add_watch(chan,
+ G_IO_IN | G_IO_ERR | G_IO_HUP
+ | G_IO_NVAL,
+ (GIOFunc) session_cb, session);
+
+ dev = manager_find_device(&session->dst,
+ AUDIO_CONTROL_INTERFACE, FALSE);
+ if (dev)
+ avrcp_connect(dev);
+ }
+ else if (session->pending_open)
+ handle_transport_connect(session, sk, l2o.imtu, l2o.omtu);
+ else {
+ err = -EIO;
+ goto failed;
+ }
+
+ process_queue(session);
+
+ return;
+
+failed:
+ if (session->pending_open) {
+ avdtp_sep_set_state(session, session->pending_open->lsep,
+ AVDTP_STATE_IDLE);
+ session->pending_open = NULL;
+ } else
+ connection_lost(session, -err);
+
+ return;
+}
+
+static int l2cap_connect(struct avdtp *session)
+{
+ int err;
+
+ err = bt_l2cap_connect(&session->src, &session->dst, AVDTP_PSM, 0,
+ l2cap_connect_cb, session);
+ if (err < 0) {
+ error("Connect failed. %s(%d)", strerror(-err), -err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void queue_request(struct avdtp *session, struct pending_req *req,
+ gboolean priority)
+{
+ if (priority)
+ session->prio_queue = g_slist_append(session->prio_queue, req);
+ else
+ session->req_queue = g_slist_append(session->req_queue, req);
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+ 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;
+
+ req = session->req;
+ session->req = NULL;
+
+ avdtp_error_init(&err, AVDTP_ERROR_ERRNO, ETIMEDOUT);
+
+ seid = ((struct seid_req *) (req->msg))->acp_seid;
+
+ stream = find_stream_by_rseid(session, seid);
+
+ if (stream)
+ lsep = stream->lsep;
+ else
+ lsep = NULL;
+
+ switch (req->msg->signal_id) {
+ case AVDTP_RECONFIGURE:
+ error("Reconfigure request timed out");
+ if (lsep && lsep->cfm && lsep->cfm->reconfigure)
+ lsep->cfm->reconfigure(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_OPEN:
+ error("Open request timed out");
+ if (lsep && lsep->cfm && lsep->cfm->open)
+ lsep->cfm->open(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_START:
+ error("Start request timed out");
+ if (lsep && lsep->cfm && lsep->cfm->start)
+ lsep->cfm->start(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_SUSPEND:
+ error("Suspend request timed out");
+ if (lsep && lsep->cfm && lsep->cfm->suspend)
+ lsep->cfm->suspend(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_CLOSE:
+ error("Close request timed out");
+ if (lsep && lsep->cfm && lsep->cfm->close)
+ lsep->cfm->close(session, lsep, stream, &err,
+ lsep->user_data);
+ break;
+ case AVDTP_SET_CONFIGURATION:
+ error("SetConfiguration request timed out");
+ if (lsep && lsep->cfm && lsep->cfm->set_configuration)
+ lsep->cfm->set_configuration(session, lsep, stream,
+ &err, lsep->user_data);
+ goto failed;
+ case AVDTP_DISCOVER:
+ error("Discover request timed out");
+ goto failed;
+ case AVDTP_GET_CAPABILITIES:
+ error("GetCapabilities request timed out");
+ goto failed;
+ case AVDTP_ABORT:
+ error("Abort request timed out");
+ goto failed;
+ }
+
+ memset(&sreq, 0, sizeof(sreq));
+ init_request(&sreq.header, AVDTP_ABORT);
+ sreq.acp_seid = seid;
+
+ if (send_request(session, TRUE, stream, &sreq, sizeof(sreq)) < 0) {
+ error("Unable to send abort request");
+ goto failed;
+ }
+
+ goto done;
+
+failed:
+ connection_lost(session, -ETIMEDOUT);
+done:
+ pending_req_free(req);
+ return FALSE;
+}
+
+static int send_req(struct avdtp *session, gboolean priority,
+ struct pending_req *req)
+{
+ int err;
+
+ if (session->state == AVDTP_SESSION_STATE_DISCONNECTED) {
+ err = l2cap_connect(session);
+ if (err < 0)
+ goto failed;
+ }
+
+ if (session->state < AVDTP_SESSION_STATE_CONNECTED ||
+ session->req != NULL) {
+ queue_request(session, req, priority);
+ return 0;
+ }
+
+ /* FIXME: Should we retry to send if the buffer
+ was not totally sent or in case of EINTR? */
+ if (!avdtp_send(session, req->msg, req->msg_size)) {
+ err = -EIO;
+ goto failed;
+ }
+
+ session->req = req;
+
+ req->timeout = g_timeout_add(REQ_TIMEOUT, request_timeout,
+ session);
+ return 0;
+
+failed:
+ g_free(req->msg);
+ g_free(req);
+ return err;
+}
+
+static int send_request(struct avdtp *session, gboolean priority,
+ struct avdtp_stream *stream, void *buffer, int size)
+{
+ struct pending_req *req;
+
+ req = g_new0(struct pending_req, 1);
+ req->msg = g_malloc(size);
+ memcpy(req->msg, buffer, size);
+ req->msg_size = size;
+ req->stream = stream;
+
+ return send_req(session, priority, req);
+}
+
+static gboolean avdtp_discover_resp(struct avdtp *session,
+ struct discover_resp *resp, int size)
+{
+ int sep_count, i, isize = sizeof(struct seid_info);
+
+ sep_count = (size - sizeof(struct avdtp_header)) / isize;
+
+ for (i = 0; i < sep_count; i++) {
+ struct avdtp_remote_sep *sep;
+ struct avdtp_stream *stream;
+ struct seid_req req;
+ int ret;
+
+ debug("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);
+
+ stream = find_stream_by_rseid(session, resp->seps[i].seid);
+
+ sep = find_remote_sep(session->seps, resp->seps[i].seid);
+ if (!sep) {
+ if (resp->seps[i].inuse && !stream)
+ continue;
+ sep = g_new0(struct avdtp_remote_sep, 1);
+ session->seps = g_slist_append(session->seps, sep);
+ }
+
+ sep->stream = stream;
+ sep->seid = resp->seps[i].seid;
+ sep->type = resp->seps[i].type;
+ sep->media_type = resp->seps[i].media_type;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_GET_CAPABILITIES);
+ req.acp_seid = sep->seid;
+
+ ret = send_request(session, TRUE, NULL, &req, sizeof(req));
+ if (ret < 0) {
+ finalize_discovery(session, ret);
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean avdtp_get_capabilities_resp(struct avdtp *session,
+ struct getcap_resp *resp,
+ int size)
+{
+ struct avdtp_remote_sep *sep;
+ uint8_t seid;
+
+ /* Check for minimum required packet size includes:
+ * 1. getcap resp header
+ * 2. media transport capability (2 bytes)
+ * 3. media codec capability type + length (2 bytes)
+ * 4. the actual media codec elements
+ * */
+ if (size < (sizeof(struct getcap_resp) + 4 +
+ sizeof(struct avdtp_media_codec_capability))) {
+ error("Too short getcap resp packet");
+ return FALSE;
+ }
+
+ seid = ((struct seid_req *) session->req->msg)->acp_seid;
+
+ sep = find_remote_sep(session->seps, seid);
+
+ debug("seid %d type %d media %d", sep->seid,
+ sep->type, sep->media_type);
+
+ if (sep->caps) {
+ g_slist_foreach(sep->caps, (GFunc) g_free, NULL);
+ g_slist_free(sep->caps);
+ sep->caps = NULL;
+ sep->codec = NULL;
+ }
+
+ sep->caps = caps_to_list(resp->caps, size - sizeof(struct getcap_resp),
+ &sep->codec);
+
+ return TRUE;
+}
+
+static gboolean avdtp_set_configuration_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_header *resp,
+ int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (sep->cfm && sep->cfm->set_configuration)
+ sep->cfm->set_configuration(session, sep, stream, NULL,
+ sep->user_data);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
+
+ return TRUE;
+}
+
+static gboolean avdtp_reconfigure_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_header *resp, int size)
+{
+ return TRUE;
+}
+
+static gboolean avdtp_open_resp(struct avdtp *session, struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (l2cap_connect(session) < 0) {
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
+ return FALSE;
+ }
+
+ session->pending_open = stream;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+
+ return TRUE;
+}
+
+static gboolean avdtp_start_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (sep->cfm && sep->cfm->start)
+ sep->cfm->start(session, sep, stream, NULL, sep->user_data);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
+
+ return TRUE;
+}
+
+static gboolean avdtp_close_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
+
+ close(stream->sock);
+ stream->sock = -1;
+
+ return TRUE;
+}
+
+static gboolean avdtp_suspend_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct gen_resp *resp,
+ int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
+
+ stream->idle_timer = g_timeout_add(STREAM_TIMEOUT,
+ (GSourceFunc) stream_timeout, stream);
+
+ if (sep->cfm && sep->cfm->suspend)
+ sep->cfm->suspend(session, sep, stream, NULL, sep->user_data);
+
+ return TRUE;
+}
+
+static gboolean avdtp_abort_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct seid_rej *resp, int size)
+{
+ struct avdtp_local_sep *sep = stream->lsep;
+
+ if (sep->cfm && sep->cfm->abort)
+ sep->cfm->abort(session, sep, stream, NULL, sep->user_data);
+
+ avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
+
+ return TRUE;
+}
+
+static gboolean avdtp_parse_resp(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_header *header, int size)
+{
+ struct avdtp_header *next;
+
+ if (session->prio_queue)
+ next = ((struct pending_req *)
+ (session->prio_queue->data))->msg;
+ else if (session->req_queue)
+ next = ((struct pending_req *)
+ (session->req_queue->data))->msg;
+ else
+ next = NULL;
+
+ switch (header->signal_id) {
+ case AVDTP_DISCOVER:
+ debug("DISCOVER request succeeded");
+ return avdtp_discover_resp(session, (void *) header, size);
+ case AVDTP_GET_CAPABILITIES:
+ debug("GET_CAPABILITIES request succeeded");
+ if (!avdtp_get_capabilities_resp(session,
+ (void *) header, size))
+ return FALSE;
+ if (!(next && next->signal_id == AVDTP_GET_CAPABILITIES))
+ finalize_discovery(session, 0);
+ return TRUE;
+ case AVDTP_SET_CONFIGURATION:
+ debug("SET_CONFIGURATION request succeeded");
+ return avdtp_set_configuration_resp(session, stream,
+ (void *) header, size);
+ case AVDTP_RECONFIGURE:
+ debug("RECONFIGURE request succeeded");
+ return avdtp_reconfigure_resp(session, stream,
+ (void *) header, size);
+ case AVDTP_OPEN:
+ debug("OPEN request succeeded");
+ return avdtp_open_resp(session, stream, (void *) header, size);
+ case AVDTP_SUSPEND:
+ debug("SUSPEND request succeeded");
+ return avdtp_suspend_resp(session, stream,
+ (void *) header, size);
+ case AVDTP_START:
+ debug("START request succeeded");
+ return avdtp_start_resp(session, stream, (void *) header, size);
+ case AVDTP_CLOSE:
+ debug("CLOSE request succeeded");
+ return avdtp_close_resp(session, stream, (void *) header, size);
+ case AVDTP_ABORT:
+ debug("ABORT request succeeded");
+ return avdtp_abort_resp(session, stream, (void *) header, size);
+ }
+
+ error("Unknown signal id in accept response: %u", header->signal_id);
+
+ return TRUE;
+}
+
+static gboolean seid_rej_to_err(struct seid_rej *rej, int size,
+ struct avdtp_error *err)
+{
+ if (size < sizeof(struct seid_rej)) {
+ error("Too small packet for seid_rej");
+ return FALSE;
+ }
+
+ avdtp_error_init(err, AVDTP_ERROR_ERROR_CODE, rej->error);
+
+ return TRUE;
+}
+
+static gboolean conf_rej_to_err(struct conf_rej *rej, int size,
+ struct avdtp_error *err, uint8_t *category)
+{
+ if (size < sizeof(struct conf_rej)) {
+ error("Too small packet for conf_rej");
+ return FALSE;
+ }
+
+ avdtp_error_init(err, AVDTP_ERROR_ERROR_CODE, rej->error);
+
+ if (category)
+ *category = rej->category;
+
+ return TRUE;
+}
+
+static gboolean stream_rej_to_err(struct stream_rej *rej, int size,
+ struct avdtp_error *err,
+ uint8_t *acp_seid)
+{
+ if (size < sizeof(struct conf_rej)) {
+ error("Too small packet for stream_rej");
+ return FALSE;
+ }
+
+ avdtp_error_init(err, AVDTP_ERROR_ERROR_CODE, rej->error);
+
+ if (acp_seid)
+ *acp_seid = rej->acp_seid;
+
+ return TRUE;
+}
+
+static gboolean avdtp_parse_rej(struct avdtp *session,
+ struct avdtp_stream *stream,
+ struct avdtp_header *header, int size)
+{
+ struct avdtp_error err;
+ uint8_t acp_seid, category;
+ struct avdtp_local_sep *sep = stream ? stream->lsep : NULL;
+
+ switch (header->signal_id) {
+ case AVDTP_DISCOVER:
+ if (!seid_rej_to_err((void *) header, size, &err))
+ return FALSE;
+ error("DISCOVER request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ return TRUE;
+ case AVDTP_GET_CAPABILITIES:
+ if (!seid_rej_to_err((void *) header, size, &err))
+ return FALSE;
+ error("GET_CAPABILITIES request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ return TRUE;
+ case AVDTP_OPEN:
+ if (!seid_rej_to_err((void *) header, size, &err))
+ return FALSE;
+ error("OPEN request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->open)
+ sep->cfm->open(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_SET_CONFIGURATION:
+ if (!conf_rej_to_err((void *) header, size, &err, &category))
+ return FALSE;
+ error("SET_CONFIGURATION request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->set_configuration)
+ sep->cfm->set_configuration(session, sep, stream,
+ &err, sep->user_data);
+ return TRUE;
+ case AVDTP_RECONFIGURE:
+ if (!conf_rej_to_err((void *) header, size, &err, &category))
+ return FALSE;
+ error("RECONFIGURE request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->reconfigure)
+ sep->cfm->reconfigure(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_START:
+ if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
+ return FALSE;
+ error("START request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->start)
+ sep->cfm->start(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_SUSPEND:
+ if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
+ return FALSE;
+ error("SUSPEND request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->suspend)
+ sep->cfm->suspend(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_CLOSE:
+ if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
+ return FALSE;
+ error("CLOSE request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->close)
+ sep->cfm->close(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ case AVDTP_ABORT:
+ if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
+ return FALSE;
+ error("ABORT request rejected: %s (%d)",
+ avdtp_strerror(&err), err.err.error_code);
+ if (sep && sep->cfm && sep->cfm->abort)
+ sep->cfm->abort(session, sep, stream, &err,
+ sep->user_data);
+ return TRUE;
+ default:
+ error("Unknown reject response signal id: %u",
+ header->signal_id);
+ return TRUE;
+ }
+}
+
+static struct avdtp *find_session(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ GSList *l;
+
+ for (l = sessions; l != NULL; l = g_slist_next(l)) {
+ struct avdtp *s = l->data;
+
+ if (bacmp(src, &s->src) || bacmp(dst, &s->dst))
+ continue;
+
+ return s;
+ }
+
+ return NULL;
+}
+
+static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct avdtp *session;
+
+ assert(src != NULL);
+ assert(dst != NULL);
+
+ session = find_session(src, dst);
+ if (session) {
+ if (session->pending_auth)
+ return NULL;
+ else
+ return session;
+ }
+
+ session = g_new0(struct avdtp, 1);
+
+ session->sock = -1;
+ bacpy(&session->src, src);
+ bacpy(&session->dst, dst);
+ session->ref = 1;
+ session->state = AVDTP_SESSION_STATE_DISCONNECTED;
+
+ sessions = g_slist_append(sessions, session);
+
+ return session;
+}
+
+struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct avdtp *session;
+
+ session = avdtp_get_internal(src, dst);
+
+ if (!session)
+ return NULL;
+
+ return avdtp_ref(session);
+}
+
+gboolean avdtp_is_connected(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct avdtp *session;
+
+ session = find_session(src, dst);
+
+ if (!session)
+ return FALSE;
+
+ if (session->state != AVDTP_SESSION_STATE_DISCONNECTED)
+ return TRUE;
+
+ return FALSE;
+}
+
+gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
+ struct avdtp_service_capability *cap)
+{
+ GSList *l;
+ struct avdtp_service_capability *stream_cap;
+
+ for (l = stream->caps; l; l = g_slist_next(l)) {
+ stream_cap = l->data;
+ if (stream_cap->category == cap->category &&
+ stream_cap->length == cap->length) {
+ if (!memcmp(stream_cap->data, cap->data, cap->length))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
+ GSList *caps)
+{
+ GSList *l;
+
+ for (l = caps; l; l = g_slist_next(l)) {
+ struct avdtp_service_capability *cap = l->data;
+
+ if (!avdtp_stream_has_capability(stream, cap))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
+ uint16_t *imtu, uint16_t *omtu,
+ GSList **caps)
+{
+ if (stream->sock < 0)
+ return FALSE;
+
+ if (sock)
+ *sock = stream->sock;
+
+ if (omtu)
+ *omtu = stream->omtu;
+
+ if (imtu)
+ *imtu = stream->imtu;
+
+ if (caps)
+ *caps = stream->caps;
+
+ return TRUE;
+}
+
+static int process_queue(struct avdtp *session)
+{
+ GSList **queue, *l;
+ struct pending_req *req;
+
+ if (session->req)
+ return 0;
+
+ if (session->prio_queue)
+ queue = &session->prio_queue;
+ else
+ queue = &session->req_queue;
+
+ if (!*queue)
+ return 0;
+
+ l = *queue;
+ req = l->data;
+
+ *queue = g_slist_remove(*queue, req);
+
+ return send_req(session, FALSE, req);
+}
+
+struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep)
+{
+ return sep->codec;
+}
+
+struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
+ void *data, int length)
+{
+ struct avdtp_service_capability *cap;
+
+ if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_MEDIA_CODEC)
+ return NULL;
+
+ cap = g_malloc(sizeof(struct avdtp_service_capability) + length);
+ cap->category = category;
+ cap->length = length;
+ memcpy(cap->data, data, length);
+
+ return cap;
+}
+
+int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
+ void *user_data)
+{
+ struct gen_req req;
+ int ret;
+
+ if (session->discov_cb)
+ return -EBUSY;
+
+ if (session->seps) {
+ cb(session, session->seps, NULL, user_data);
+ return 0;
+ }
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_DISCOVER);
+
+ ret = send_request(session, FALSE, NULL, &req, sizeof(req));
+ if (ret == 0) {
+ session->discov_cb = cb;
+ session->user_data = user_data;
+ }
+
+ return ret;
+}
+
+int avdtp_get_seps(struct avdtp *session, uint8_t acp_type, uint8_t media_type,
+ uint8_t codec, struct avdtp_local_sep **lsep,
+ struct avdtp_remote_sep **rsep)
+{
+ GSList *l;
+ uint8_t int_type;
+
+ int_type = acp_type == AVDTP_SEP_TYPE_SINK ?
+ AVDTP_SEP_TYPE_SOURCE : AVDTP_SEP_TYPE_SINK;
+
+ *lsep = find_local_sep(int_type, media_type, codec);
+ if (!*lsep)
+ return -EINVAL;
+
+ for (l = session->seps; l != NULL; l = g_slist_next(l)) {
+ struct avdtp_remote_sep *sep = l->data;
+ struct avdtp_service_capability *cap;
+ struct avdtp_media_codec_capability *codec_data;
+
+ if (sep->type != acp_type)
+ continue;
+
+ if (sep->media_type != media_type)
+ continue;
+
+ if (!sep->codec)
+ continue;
+
+ cap = sep->codec;
+ codec_data = (void *) cap->data;
+
+ if (codec_data->media_codec_type != codec)
+ continue;
+
+ if (!sep->stream) {
+ *rsep = sep;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+gboolean avdtp_stream_remove_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ unsigned int id)
+{
+ GSList *l;
+ struct stream_callback *cb;
+
+ for (cb = NULL, l = stream->callbacks; l != NULL; l = l->next) {
+ struct stream_callback *tmp = l->data;
+ if (tmp->id == id) {
+ cb = tmp;
+ break;
+ }
+ }
+
+ if (!cb)
+ return FALSE;
+
+ stream->callbacks = g_slist_remove(stream->callbacks, cb);
+ g_free(cb);
+
+ return TRUE;
+}
+
+unsigned int avdtp_stream_add_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ avdtp_stream_state_cb cb, void *data)
+{
+ struct stream_callback *stream_cb;
+ static unsigned int id = 0;
+
+ stream_cb = g_new(struct stream_callback, 1);
+ stream_cb->cb = cb;
+ stream_cb->user_data = data;
+ stream_cb->id = ++id;
+
+ stream->callbacks = g_slist_append(stream->callbacks, stream_cb);;
+
+ return stream_cb->id;
+}
+
+int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+
+ if (session->state < AVDTP_SESSION_STATE_CONNECTED)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_GET_CONFIGURATION);
+ req.acp_seid = stream->rseid;
+
+ return send_request(session, FALSE, stream, &req, sizeof(req));
+}
+
+static void copy_capabilities(gpointer data, gpointer user_data)
+{
+ struct avdtp_service_capability *src_cap = data;
+ struct avdtp_service_capability *dst_cap;
+ GSList **l = user_data;
+
+ dst_cap = avdtp_service_cap_new(src_cap->category, src_cap->data,
+ src_cap->length);
+
+ *l = g_slist_append(*l, dst_cap);
+}
+
+int avdtp_set_configuration(struct avdtp *session,
+ struct avdtp_remote_sep *rsep,
+ struct avdtp_local_sep *lsep,
+ GSList *caps,
+ struct avdtp_stream **stream)
+{
+ struct setconf_req *req;
+ struct avdtp_stream *new_stream;
+ unsigned char *ptr;
+ int ret, caps_len;
+ struct avdtp_service_capability *cap;
+ GSList *l;
+
+ if (session->state != AVDTP_SESSION_STATE_CONNECTED)
+ return -ENOTCONN;
+
+ if (!(lsep && rsep))
+ return -EINVAL;
+
+ debug("avdtp_set_configuration(%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;
+
+ g_slist_foreach(caps, copy_capabilities, &new_stream->caps);
+
+ /* Calculate total size of request */
+ for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {
+ cap = l->data;
+ caps_len += cap->length + 2;
+ }
+
+ req = g_malloc0(sizeof(struct setconf_req) + caps_len);
+
+ init_request(&req->header, AVDTP_SET_CONFIGURATION);
+ req->int_seid = lsep->info.seid;
+ req->acp_seid = rsep->seid;
+
+ /* Copy the capabilities into the request */
+ for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {
+ cap = l->data;
+ memcpy(ptr, cap, cap->length + 2);
+ ptr += cap->length + 2;
+ }
+
+ ret = send_request(session, FALSE, new_stream, req,
+ sizeof(struct setconf_req) + caps_len);
+ if (ret < 0)
+ stream_free(new_stream);
+ else {
+ lsep->info.inuse = 1;
+ lsep->stream = new_stream;
+ rsep->stream = new_stream;
+ session->streams = g_slist_append(session->streams, new_stream);
+ if (stream)
+ *stream = new_stream;
+ }
+
+ g_free(req);
+
+ return ret;
+}
+
+int avdtp_reconfigure(struct avdtp *session, GSList *caps,
+ struct avdtp_stream *stream)
+{
+ struct reconf_req *req;
+ unsigned char *ptr;
+ int caps_len;
+ GSList *l;
+ struct avdtp_service_capability *cap;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state != AVDTP_STATE_OPEN)
+ return -EINVAL;
+
+ /* Calculate total size of request */
+ for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {
+ cap = l->data;
+ caps_len += cap->length + 2;
+ }
+
+ req = g_malloc0(sizeof(struct reconf_req) + caps_len);
+
+ init_request(&req->header, AVDTP_RECONFIGURE);
+ req->acp_seid = stream->rseid;
+
+ /* Copy the capabilities into the request */
+ for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {
+ cap = l->data;
+ memcpy(ptr, cap, cap->length + 2);
+ ptr += cap->length + 2;
+ }
+
+ return send_request(session, FALSE, stream, req, sizeof(*req)
+ + caps_len);
+}
+
+int avdtp_open(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state > AVDTP_STATE_CONFIGURED)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_OPEN);
+ req.acp_seid = stream->rseid;
+
+ return send_request(session, FALSE, stream, &req, sizeof(req));
+}
+
+int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct start_req req;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state != AVDTP_STATE_OPEN)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_START);
+ req.first_seid.seid = stream->rseid;
+
+ return send_request(session, FALSE, stream, &req, sizeof(req));
+}
+
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+ int ret;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state < AVDTP_STATE_OPEN)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_CLOSE);
+ req.acp_seid = stream->rseid;
+
+ ret = send_request(session, FALSE, stream, &req, sizeof(req));
+ if (ret == 0)
+ stream->close_int = TRUE;
+
+ return ret;
+}
+
+int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state <= AVDTP_STATE_OPEN)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_SUSPEND);
+ req.acp_seid = stream->rseid;
+
+ return send_request(session, FALSE, stream, &req, sizeof(req));
+}
+
+int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
+{
+ struct seid_req req;
+ int ret;
+
+ if (!g_slist_find(session->streams, stream))
+ return -EINVAL;
+
+ if (stream->lsep->state <= AVDTP_STATE_OPEN)
+ return -EINVAL;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_ABORT);
+ req.acp_seid = stream->rseid;
+
+ ret = send_request(session, FALSE, stream, &req, sizeof(req));
+ if (ret == 0)
+ avdtp_sep_set_state(session, stream->lsep,
+ AVDTP_STATE_ABORTING);
+
+ return 0;
+}
+
+struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+ uint8_t codec_type,
+ struct avdtp_sep_ind *ind,
+ struct avdtp_sep_cfm *cfm,
+ void *user_data)
+{
+ struct avdtp_local_sep *sep;
+
+ if (free_seid > MAX_SEID)
+ return NULL;
+
+ sep = g_new0(struct avdtp_local_sep, 1);
+
+ sep->state = AVDTP_STATE_IDLE;
+ sep->info.seid = free_seid++;
+ sep->info.type = type;
+ sep->info.media_type = media_type;
+ sep->codec = codec_type;
+ sep->ind = ind;
+ sep->cfm = cfm;
+ sep->user_data = user_data;
+
+ debug("SEP %p registered: type:%d codec:%d seid:%d", sep,
+ sep->info.type, sep->codec, sep->info.seid);
+ local_seps = g_slist_append(local_seps, sep);
+
+ return sep;
+}
+
+int avdtp_unregister_sep(struct avdtp_local_sep *sep)
+{
+ if (!sep)
+ return -EINVAL;
+
+ if (sep->info.inuse)
+ return -EBUSY;
+
+ local_seps = g_slist_remove(local_seps, sep);
+
+ g_free(sep);
+
+ return 0;
+}
+
+static void auth_cb(DBusError *derr, void *user_data)
+{
+ struct avdtp *session = user_data;
+ struct audio_device *dev;
+ GIOChannel *io;
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Access denied: %s", derr->message);
+ if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {
+ debug("Canceling authorization request");
+ service_cancel_auth(&session->src, &session->dst);
+ }
+
+ connection_lost(session, -EACCES);
+ return;
+ }
+
+ session->buf = g_malloc0(session->mtu);
+
+ set_disconnect_timer(session);
+
+ session->state = AVDTP_SESSION_STATE_CONNECTED;
+
+ dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE,
+ FALSE);
+ if (dev)
+ avrcp_connect(dev);
+
+ g_source_remove(session->io);
+
+ io = g_io_channel_unix_new(session->sock);
+ session->io = g_io_add_watch(io,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) session_cb, session);
+ g_io_channel_unref(io);
+}
+
+static void avdtp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer data)
+{
+ int sk;
+ socklen_t size;
+ struct l2cap_options l2o;
+ struct avdtp *session;
+ char address[18];
+
+ if (err < 0) {
+ error("accept: %s (%d)", strerror(-err), -err);
+ return;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ ba2str(dst, address);
+ debug("AVDTP: incoming connect from %s", address);
+
+ memset(&l2o, 0, sizeof(l2o));
+ size = sizeof(l2o);
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &size) < 0) {
+ error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(errno),
+ errno);
+ goto drop;
+ }
+
+ session = avdtp_get_internal(src, dst);
+
+ if (session->pending_open && session->pending_open->open_acp) {
+ handle_transport_connect(session, sk, l2o.imtu, l2o.omtu);
+ return;
+ }
+
+ if (session->sock >= 0) {
+ error("Refusing unexpected connect from %s", address);
+ goto drop;
+ }
+
+ session->mtu = l2o.imtu;
+ session->sock = sk;
+
+ session->io = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) session_cb, session);
+ g_io_channel_unref(chan);
+
+ if (service_req_auth(src, dst, ADVANCED_AUDIO_UUID, auth_cb,
+ session) < 0) {
+ avdtp_unref(session);
+ goto drop;
+ }
+
+ return;
+
+drop:
+ g_io_channel_close(chan);
+ g_io_channel_unref(chan);
+}
+
+static GIOChannel *avdtp_server_socket(gboolean master)
+{
+ int lm;
+
+ lm = L2CAP_LM_SECURE;
+
+ if (master)
+ lm |= L2CAP_LM_MASTER;
+
+ return bt_l2cap_listen(BDADDR_ANY, AVDTP_PSM, 0, lm, avdtp_server_cb,
+ NULL);
+}
+
+const char *avdtp_strerror(struct avdtp_error *err)
+{
+ if (err->type == AVDTP_ERROR_ERRNO)
+ return strerror(err->err.posix_errno);
+
+ switch(err->err.error_code) {
+ case AVDTP_BAD_HEADER_FORMAT:
+ return "Bad Header Format";
+ case AVDTP_BAD_LENGTH:
+ return "Bad Packet Lenght";
+ case AVDTP_BAD_ACP_SEID:
+ return "Bad Acceptor SEID";
+ case AVDTP_SEP_IN_USE:
+ return "Stream End Point in Use";
+ case AVDTP_SEP_NOT_IN_USE:
+ return "Stream End Point Not in Use";
+ case AVDTP_BAD_SERV_CATEGORY:
+ return "Bad Service Category";
+ case AVDTP_BAD_PAYLOAD_FORMAT:
+ return "Bad Payload format";
+ case AVDTP_NOT_SUPPORTED_COMMAND:
+ return "Command Not Supported";
+ case AVDTP_INVALID_CAPABILITIES:
+ return "Invalid Capabilities";
+ case AVDTP_BAD_RECOVERY_TYPE:
+ return "Bad Recovery Type";
+ case AVDTP_BAD_MEDIA_TRANSPORT_FORMAT:
+ return "Bad Media Transport Format";
+ case AVDTP_BAD_RECOVERY_FORMAT:
+ return "Bad Recovery Format";
+ case AVDTP_BAD_ROHC_FORMAT:
+ return "Bad Header Compression Format";
+ case AVDTP_BAD_CP_FORMAT:
+ return "Bad Content Protetion Format";
+ case AVDTP_BAD_MULTIPLEXING_FORMAT:
+ return "Bad Multiplexing Format";
+ case AVDTP_UNSUPPORTED_CONFIGURATION:
+ return "Configuration not supported";
+ case AVDTP_BAD_STATE:
+ return "Bad State";
+ default:
+ return "Unknow error";
+ }
+}
+
+avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
+{
+ return sep->state;
+}
+
+void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst)
+{
+ if (src)
+ bacpy(src, &session->src);
+ if (dst)
+ bacpy(dst, &session->dst);
+}
+
+int avdtp_init(GKeyFile *config)
+{
+ GError *err = NULL;
+ gboolean tmp, master = TRUE;
+
+ if (avdtp_server)
+ return 0;
+
+ if (config) {
+ tmp = g_key_file_get_boolean(config, "General",
+ "Master", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ } else
+ master = tmp;
+ }
+
+ avdtp_server = avdtp_server_socket(master);
+ if (!avdtp_server)
+ return -1;
+
+ return 0;
+}
+
+void avdtp_exit(void)
+{
+ if (!avdtp_server)
+ return;
+
+ g_io_channel_close(avdtp_server);
+ g_io_channel_unref(avdtp_server);
+ avdtp_server = NULL;
+}
+
+gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
+{
+ return g_slist_find(session->streams, stream) ? TRUE : FALSE;
+}
diff --git a/utils/audio/avdtp.h b/utils/audio/avdtp.h
new file mode 100644
index 00000000..de7e6e3d
--- /dev/null
+++ b/utils/audio/avdtp.h
@@ -0,0 +1,268 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+typedef enum {
+ AVDTP_ERROR_ERRNO,
+ AVDTP_ERROR_ERROR_CODE
+} avdtp_error_type_t;
+
+struct avdtp;
+struct avdtp_stream;
+struct avdtp_local_sep;
+struct avdtp_remote_sep;
+struct avdtp_error {
+ avdtp_error_type_t type;
+ union {
+ uint8_t error_code;
+ int posix_errno;
+ } err;
+};
+
+/* SEP capability categories */
+#define AVDTP_MEDIA_TRANSPORT 0x01
+#define AVDTP_REPORTING 0x02
+#define AVDTP_RECOVERY 0x03
+#define AVDTP_CONTENT_PROTECTION 0x04
+#define AVDTP_HEADER_COMPRESSION 0x05
+#define AVDTP_MULTIPLEXING 0x06
+#define AVDTP_MEDIA_CODEC 0x07
+
+/* AVDTP error definitions */
+#define AVDTP_BAD_HEADER_FORMAT 0x01
+#define AVDTP_BAD_LENGTH 0x11
+#define AVDTP_BAD_ACP_SEID 0x12
+#define AVDTP_SEP_IN_USE 0x13
+#define AVDTP_SEP_NOT_IN_USE 0x14
+#define AVDTP_BAD_SERV_CATEGORY 0x17
+#define AVDTP_BAD_PAYLOAD_FORMAT 0x18
+#define AVDTP_NOT_SUPPORTED_COMMAND 0x19
+#define AVDTP_INVALID_CAPABILITIES 0x1A
+#define AVDTP_BAD_RECOVERY_TYPE 0x22
+#define AVDTP_BAD_MEDIA_TRANSPORT_FORMAT 0x23
+#define AVDTP_BAD_RECOVERY_FORMAT 0x25
+#define AVDTP_BAD_ROHC_FORMAT 0x26
+#define AVDTP_BAD_CP_FORMAT 0x27
+#define AVDTP_BAD_MULTIPLEXING_FORMAT 0x28
+#define AVDTP_UNSUPPORTED_CONFIGURATION 0x29
+#define AVDTP_BAD_STATE 0x31
+
+/* SEP types definitions */
+#define AVDTP_SEP_TYPE_SOURCE 0x00
+#define AVDTP_SEP_TYPE_SINK 0x01
+
+/* Media types definitions */
+#define AVDTP_MEDIA_TYPE_AUDIO 0x00
+#define AVDTP_MEDIA_TYPE_VIDEO 0x01
+#define AVDTP_MEDIA_TYPE_MULTIMEDIA 0x02
+
+typedef enum {
+ AVDTP_STATE_IDLE,
+ AVDTP_STATE_CONFIGURED,
+ AVDTP_STATE_OPEN,
+ AVDTP_STATE_STREAMING,
+ AVDTP_STATE_CLOSING,
+ AVDTP_STATE_ABORTING,
+} avdtp_state_t;
+
+struct avdtp_service_capability {
+ uint8_t category;
+ uint8_t length;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avdtp_media_codec_capability {
+ uint8_t rfa0:4;
+ uint8_t media_type:4;
+ uint8_t media_codec_type;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_media_codec_capability {
+ uint8_t media_type:4;
+ uint8_t rfa0:4;
+ uint8_t media_codec_type;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+typedef void (*avdtp_stream_state_cb) (struct avdtp_stream *stream,
+ avdtp_state_t old_state,
+ avdtp_state_t new_state,
+ struct avdtp_error *err,
+ void *user_data);
+
+/* Callbacks for when a reply is received to a command that we sent */
+struct avdtp_sep_cfm {
+ void (*set_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data);
+ void (*get_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data);
+ void (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data);
+ void (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data);
+ void (*suspend) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+ void (*close) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+ void (*abort) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data);
+ void (*reconfigure) (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
+ * indicates whether the command should be rejected or accepted */
+struct avdtp_sep_ind {
+ gboolean (*get_capability) (struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ GSList **caps, uint8_t *err,
+ void *user_data);
+ gboolean (*set_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream,
+ GSList *caps, uint8_t *err,
+ uint8_t *category, void *user_data);
+ gboolean (*get_configuration) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t *err, void *user_data);
+ gboolean (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*suspend) (struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*close) (struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*abort) (struct avdtp *session, struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
+ gboolean (*reconfigure) (struct avdtp *session,
+ struct avdtp_local_sep *lsep,
+ uint8_t *err, void *user_data);
+};
+
+typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
+ struct avdtp_error *err, void *user_data);
+
+struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst);
+
+void avdtp_unref(struct avdtp *session);
+struct avdtp *avdtp_ref(struct avdtp *session);
+
+gboolean avdtp_is_connected(const bdaddr_t *src, const bdaddr_t *dst);
+
+struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
+ void *data, int size);
+
+struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep);
+
+int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
+ void *user_data);
+
+gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream);
+
+unsigned int avdtp_stream_add_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ avdtp_stream_state_cb cb, void *data);
+gboolean avdtp_stream_remove_cb(struct avdtp *session,
+ struct avdtp_stream *stream,
+ unsigned int id);
+
+gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
+ uint16_t *imtu, uint16_t *omtu,
+ GSList **caps);
+
+gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
+ struct avdtp_service_capability *cap);
+gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
+ GSList *caps);
+
+int avdtp_set_configuration(struct avdtp *session,
+ struct avdtp_remote_sep *rsep,
+ struct avdtp_local_sep *lsep,
+ GSList *caps,
+ struct avdtp_stream **stream);
+
+int avdtp_get_configuration(struct avdtp *session,
+ struct avdtp_stream *stream);
+
+int avdtp_open(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_reconfigure(struct avdtp *session, GSList *caps,
+ struct avdtp_stream *stream);
+int avdtp_start(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
+
+struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+ uint8_t codec_type,
+ struct avdtp_sep_ind *ind,
+ struct avdtp_sep_cfm *cfm,
+ void *user_data);
+
+/* Find a matching pair of local and remote SEP ID's */
+int avdtp_get_seps(struct avdtp *session, uint8_t type, uint8_t media,
+ uint8_t codec, struct avdtp_local_sep **lsep,
+ struct avdtp_remote_sep **rsep);
+
+int avdtp_unregister_sep(struct avdtp_local_sep *sep);
+
+avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
+
+void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id);
+const char *avdtp_strerror(struct avdtp_error *err);
+avdtp_error_type_t avdtp_error_type(struct avdtp_error *err);
+int avdtp_error_error_code(struct avdtp_error *err);
+int avdtp_error_posix_errno(struct avdtp_error *err);
+
+void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst);
+
+int avdtp_init(GKeyFile *config);
+void avdtp_exit(void);
diff --git a/utils/audio/control.c b/utils/audio/control.c
new file mode 100644
index 00000000..9139213b
--- /dev/null
+++ b/utils/audio/control.c
@@ -0,0 +1,949 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/l2cap.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "dbus-service.h"
+#include "logging.h"
+#include "uinput.h"
+#include "device.h"
+#include "manager.h"
+#include "avdtp.h"
+#include "control.h"
+#include "sdpd.h"
+#include "glib-helper.h"
+
+#define AVCTP_PSM 23
+
+/* Message types */
+#define AVCTP_COMMAND 0
+#define AVCTP_RESPONSE 1
+
+/* Packet types */
+#define AVCTP_PACKET_SINGLE 0
+#define AVCTP_PACKET_START 1
+#define AVCTP_PACKET_CONTINUE 2
+#define AVCTP_PACKET_END 3
+
+/* ctype entries */
+#define CTYPE_CONTROL 0x0
+#define CTYPE_STATUS 0x1
+#define CTYPE_ACCEPTED 0x9
+#define CTYPE_STABLE 0xC
+
+/* opcodes */
+#define OP_UNITINFO 0x30
+#define OP_SUBUNITINFO 0x31
+#define OP_PASSTHROUGH 0x7c
+
+/* subunits of interest */
+#define SUBUNIT_PANEL 0x09
+
+/* operands in passthrough commands */
+#define VOLUP_OP 0x41
+#define VOLDOWN_OP 0x42
+#define MUTE_OP 0x43
+
+#define PLAY_OP 0x44
+#define STOP_OP 0x45
+#define PAUSE_OP 0x46
+#define REWIND_OP 0x48
+#define FAST_FORWARD_OP 0x49
+#define NEXT_OP 0x4b
+#define PREV_OP 0x4c
+
+static DBusConnection *connection = NULL;
+
+static uint32_t tg_record_id = 0;
+static uint32_t ct_record_id = 0;
+
+static GIOChannel *avctp_server = NULL;
+
+static GSList *sessions = NULL;
+
+typedef enum {
+ AVCTP_STATE_DISCONNECTED = 0,
+ AVCTP_STATE_CONNECTING,
+ AVCTP_STATE_CONNECTED
+} avctp_state_t;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avctp_header {
+ uint8_t ipid:1;
+ uint8_t cr:1;
+ uint8_t packet_type:2;
+ uint8_t transaction:4;
+ uint16_t pid;
+} __attribute__ ((packed));
+
+struct avrcp_header {
+ uint8_t code:4;
+ uint8_t _hdr0:4;
+ uint8_t subunit_id:3;
+ uint8_t subunit_type:5;
+ uint8_t opcode;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avctp_header {
+ uint8_t transaction:4;
+ uint8_t packet_type:2;
+ uint8_t cr:1;
+ uint8_t ipid:1;
+ uint16_t pid;
+} __attribute__ ((packed));
+
+struct avrcp_header {
+ uint8_t _hdr0:4;
+ uint8_t code:4;
+ uint8_t subunit_type:5;
+ uint8_t subunit_id:3;
+ uint8_t opcode;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct avctp {
+ struct audio_device *dev;
+
+ avctp_state_t state;
+
+ bdaddr_t src;
+ bdaddr_t dst;
+
+ int uinput;
+
+ int sock;
+
+ guint io;
+
+ uint16_t mtu;
+};
+
+struct control {
+ struct avctp *session;
+};
+
+static sdp_record_t *avrcp_ct_record()
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, avctp, avrct;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *psm, *version, *features;
+ uint16_t lp = AVCTP_PSM, ver = 0x0103, feat = 0x000f;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ /* Service Class ID List */
+ sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &avrct);
+ sdp_set_service_classes(record, svclass_id);
+
+ /* Protocol Descriptor List */
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&avctp, AVCTP_UUID);
+ proto[1] = sdp_list_append(0, &avctp);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ /* Bluetooth Profile Descriptor List */
+ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
+ profile[0].version = ver;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ features = sdp_data_alloc(SDP_UINT16, &feat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ sdp_set_info_attr(record, "AVRCP CT", 0, 0);
+
+ free(psm);
+ free(version);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static sdp_record_t *avrcp_tg_record()
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, avctp, avrtg;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *psm, *version, *features;
+ uint16_t lp = AVCTP_PSM, ver = 0x0103, feat = 0x000f;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ /* Service Class ID List */
+ sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &avrtg);
+ sdp_set_service_classes(record, svclass_id);
+
+ /* Protocol Descriptor List */
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&avctp, AVCTP_UUID);
+ proto[1] = sdp_list_append(0, &avctp);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ /* Bluetooth Profile Descriptor List */
+ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
+ profile[0].version = ver;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ features = sdp_data_alloc(SDP_UINT16, &feat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ sdp_set_info_attr(record, "AVRCP TG", 0, 0);
+
+ free(psm);
+ free(version);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static struct avctp *find_session(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ GSList *l;
+
+ for (l = sessions; l != NULL; l = g_slist_next(l)) {
+ struct avctp *s = l->data;
+
+ if (bacmp(src, &s->src) || bacmp(dst, &s->dst))
+ continue;
+
+ return s;
+ }
+
+ return NULL;
+}
+
+static struct avctp *avctp_get(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct avctp *session;
+
+ assert(src != NULL);
+ assert(dst != NULL);
+
+ session = find_session(src, dst);
+ if (session)
+ return session;
+
+ session = g_new0(struct avctp, 1);
+
+ session->uinput = -1;
+ session->sock = -1;
+ bacpy(&session->src, src);
+ bacpy(&session->dst, dst);
+
+ sessions = g_slist_append(sessions, session);
+
+ return session;
+}
+
+static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct uinput_event event;
+
+ memset(&event, 0, sizeof(event));
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ return write(fd, &event, sizeof(event));
+}
+
+static void send_key(int fd, uint16_t key, int pressed)
+{
+ if (fd < 0)
+ return;
+
+ send_event(fd, EV_KEY, key, pressed);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+static void handle_panel_passthrough(struct avctp *session,
+ const unsigned char *operands,
+ int operand_count)
+{
+ const char *status;
+ int pressed;
+
+ if (operand_count == 0)
+ return;
+
+ if (operands[0] & 0x80) {
+ status = "released";
+ pressed = 0;
+ } else {
+ status = "pressed";
+ pressed = 1;
+ }
+
+ switch (operands[0] & 0x7F) {
+ case PLAY_OP:
+ debug("AVRCP: PLAY %s", status);
+ send_key(session->uinput, KEY_PLAYPAUSE, pressed);
+ break;
+ case STOP_OP:
+ debug("AVRCP: STOP %s", status);
+ send_key(session->uinput, KEY_STOP, pressed);
+ break;
+ case PAUSE_OP:
+ debug("AVRCP: PAUSE %s", status);
+ send_key(session->uinput, KEY_PLAYPAUSE, pressed);
+ break;
+ case NEXT_OP:
+ debug("AVRCP: NEXT %s", status);
+ send_key(session->uinput, KEY_NEXTSONG, pressed);
+ break;
+ case PREV_OP:
+ debug("AVRCP: PREV %s", status);
+ send_key(session->uinput, KEY_PREVIOUSSONG, pressed);
+ break;
+ case REWIND_OP:
+ debug("AVRCP: REWIND %s", status);
+ send_key(session->uinput, KEY_REWIND, pressed);
+ break;
+ case FAST_FORWARD_OP:
+ debug("AVRCP: FAST FORWARD %s", status);
+ send_key(session->uinput, KEY_FORWARD, pressed);
+ break;
+ default:
+ debug("AVRCP: unknown button 0x%02X %s", operands[0] & 0x7F, status);
+ break;
+ }
+}
+
+static void avctp_unref(struct avctp *session)
+{
+ sessions = g_slist_remove(sessions, session);
+
+ if (session->state == AVCTP_STATE_CONNECTED)
+ g_dbus_emit_signal(session->dev->conn,
+ session->dev->path,
+ AUDIO_CONTROL_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+ if (session->sock >= 0)
+ close(session->sock);
+ if (session->io)
+ g_source_remove(session->io);
+
+ if (session->dev)
+ session->dev->control->session = NULL;
+
+ if (session->uinput >= 0) {
+ ioctl(session->uinput, UI_DEV_DESTROY);
+ close(session->uinput);
+ }
+
+ g_free(session);
+}
+
+static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct avctp *session = data;
+ unsigned char buf[1024], *operands;
+ struct avctp_header *avctp;
+ struct avrcp_header *avrcp;
+ int ret, packet_size, operand_count;
+
+ if (!(cond | G_IO_IN))
+ goto failed;
+
+ ret = read(session->sock, buf, sizeof(buf));
+ if (ret <= 0)
+ goto failed;
+
+ debug("Got %d bytes of data for AVCTP session %p", ret, session);
+
+ if (ret < sizeof(struct avctp_header)) {
+ error("Too small AVCTP packet");
+ goto failed;
+ }
+
+ packet_size = ret;
+
+ avctp = (struct avctp_header *) buf;
+
+ debug("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "
+ "PID 0x%04X",
+ avctp->transaction, avctp->packet_type,
+ avctp->cr, avctp->ipid, ntohs(avctp->pid));
+
+ ret -= sizeof(struct avctp_header);
+ if (ret < sizeof(struct avrcp_header)) {
+ error("Too small AVRCP packet");
+ goto failed;
+ }
+
+ avrcp = (struct avrcp_header *) (buf + sizeof(struct avctp_header));
+
+ ret -= sizeof(struct avrcp_header);
+
+ 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, "
+ "opcode 0x%02X, %d operands",
+ avctp->cr ? "response" : "command",
+ avrcp->code, avrcp->subunit_type, avrcp->subunit_id,
+ avrcp->opcode, operand_count);
+
+ if (avctp->packet_type == AVCTP_PACKET_SINGLE &&
+ avctp->cr == AVCTP_COMMAND &&
+ avctp->pid == htons(AV_REMOTE_SVCLASS_ID) &&
+ avrcp->code == CTYPE_CONTROL &&
+ avrcp->subunit_type == SUBUNIT_PANEL &&
+ avrcp->opcode == OP_PASSTHROUGH) {
+ handle_panel_passthrough(session, operands, operand_count);
+ avctp->cr = AVCTP_RESPONSE;
+ avrcp->code = CTYPE_ACCEPTED;
+ ret = write(session->sock, buf, packet_size);
+ }
+
+ if (avctp->packet_type == AVCTP_PACKET_SINGLE &&
+ avctp->cr == AVCTP_COMMAND &&
+ avctp->pid == htons(AV_REMOTE_SVCLASS_ID) &&
+ avrcp->code == CTYPE_STATUS &&
+ (avrcp->opcode == OP_UNITINFO
+ || avrcp->opcode == OP_SUBUNITINFO)) {
+ avctp->cr = AVCTP_RESPONSE;
+ avrcp->code = CTYPE_STABLE;
+ debug("reply to %s", avrcp->opcode == OP_UNITINFO ?
+ "OP_UNITINFO" : "OP_SUBUNITINFO");
+ ret = write(session->sock, buf, packet_size);
+ }
+
+ return TRUE;
+
+failed:
+ debug("AVCTP session %p got disconnected", session);
+ avctp_unref(session);
+ return FALSE;
+}
+
+static int uinput_create(char *name)
+{
+ struct uinput_dev dev;
+ int fd, err;
+
+ fd = open("/dev/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/input/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/misc/uinput", O_RDWR);
+ if (fd < 0) {
+ err = errno;
+ error("Can't open input device: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+ }
+ }
+
+ memset(&dev, 0, sizeof(dev));
+ if (name)
+ strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
+
+ dev.id.bustype = BUS_BLUETOOTH;
+ dev.id.vendor = 0x0000;
+ dev.id.product = 0x0000;
+ dev.id.version = 0x0000;
+
+ if (write(fd, &dev, sizeof(dev)) < 0) {
+ err = errno;
+ error("Can't write device information: %s (%d)",
+ strerror(err), err);
+ close(fd);
+ errno = err;
+ return -err;
+ }
+
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+ ioctl(fd, UI_SET_EVBIT, EV_REP);
+ ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+ ioctl(fd, UI_SET_KEYBIT, KEY_PLAYPAUSE);
+ ioctl(fd, UI_SET_KEYBIT, KEY_STOP);
+ ioctl(fd, UI_SET_KEYBIT, KEY_NEXTSONG);
+ ioctl(fd, UI_SET_KEYBIT, KEY_PREVIOUSSONG);
+ ioctl(fd, UI_SET_KEYBIT, KEY_REWIND);
+ ioctl(fd, UI_SET_KEYBIT, KEY_FORWARD);
+
+ if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+ err = errno;
+ error("Can't create uinput device: %s (%d)",
+ strerror(err), err);
+ close(fd);
+ errno = err;
+ return -err;
+ }
+
+ return fd;
+}
+
+static void init_uinput(struct avctp *session)
+{
+ char address[18], *name;
+
+ ba2str(&session->dst, address);
+
+ name = session->dev->name ? session->dev->name : address;
+
+ session->uinput = uinput_create(name);
+ if (session->uinput < 0)
+ error("AVRCP: failed to init uinput for %s", name);
+ else
+ debug("AVRCP: uinput initialized for %s", name);
+}
+
+static void avctp_connect_session(struct avctp *session)
+{
+ GIOChannel *io;
+
+ session->state = AVCTP_STATE_CONNECTED;
+ session->dev = manager_device_connected(&session->dst,
+ AVRCP_TARGET_UUID);
+ session->dev->control->session = session;
+
+ init_uinput(session);
+
+ g_dbus_emit_signal(session->dev->conn, session->dev->path,
+ AUDIO_CONTROL_INTERFACE, "Connected",
+ DBUS_TYPE_INVALID);
+
+ if (session->io)
+ g_source_remove(session->io);
+
+ io = g_io_channel_unix_new(session->sock);
+ session->io = g_io_add_watch(io,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) session_cb, session);
+ g_io_channel_unref(io);
+}
+
+static void auth_cb(DBusError *derr, void *user_data)
+{
+ struct avctp *session = user_data;
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Access denied: %s", derr->message);
+ if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {
+ debug("Canceling authorization request");
+ service_cancel_auth(&session->src, &session->dst);
+ }
+
+ avctp_unref(session);
+ return;
+ }
+
+ avctp_connect_session(session);
+}
+
+static void avctp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer data)
+{
+ socklen_t size;
+ struct l2cap_options l2o;
+ struct avctp *session;
+ GIOCondition flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ char address[18];
+
+ if (err < 0) {
+ error("AVCTP server socket: %s (%d)", strerror(-err), -err);
+ return;
+ }
+
+ session = avctp_get(src, dst);
+
+ if (!session) {
+ error("Unable to create new AVCTP session");
+ goto drop;
+ }
+
+ if (session->sock >= 0) {
+ error("Refusing unexpected connect from %s", address);
+ goto drop;
+ }
+
+ session->state = AVCTP_STATE_CONNECTING;
+ session->sock = g_io_channel_unix_get_fd(chan);
+
+ memset(&l2o, 0, sizeof(l2o));
+ size = sizeof(l2o);
+ if (getsockopt(session->sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &size) < 0) {
+ err = errno;
+ error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err),
+ err);
+ avctp_unref(session);
+ goto drop;
+ }
+
+ session->mtu = l2o.imtu;
+
+ session->io = g_io_add_watch(chan, flags, (GIOFunc) session_cb,
+ session);
+ g_io_channel_unref(chan);
+
+ if (avdtp_is_connected(src, dst))
+ goto proceed;
+
+ if (service_req_auth(src, dst, AVRCP_TARGET_UUID, auth_cb, session) < 0)
+ goto drop;
+
+ return;
+
+proceed:
+ avctp_connect_session(session);
+
+ return;
+
+drop:
+ close(session->sock);
+}
+
+static GIOChannel *avctp_server_socket(gboolean master)
+{
+ int lm;
+ GIOChannel *io;
+
+ lm = L2CAP_LM_SECURE;
+
+ if (master)
+ lm |= L2CAP_LM_MASTER;
+
+ io = bt_l2cap_listen(BDADDR_ANY, AVCTP_PSM, 0, lm, avctp_server_cb,
+ NULL);
+ if (!io) {
+ error("Unable to allocate new io channel");
+ return NULL;
+ }
+
+ return io;
+}
+
+static void avctp_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer data)
+{
+ struct avctp *session = data;
+ struct l2cap_options l2o;
+ socklen_t len;
+ int sk;
+ char address[18];
+
+ if (err < 0) {
+ avctp_unref(session);
+ error("AVCTP connect(%s): %s (%d)", address, strerror(-err),
+ -err);
+ return;
+ }
+
+ ba2str(&session->dst, address);
+ debug("AVCTP: connected to %s", address);
+
+ g_io_channel_set_close_on_unref(chan, FALSE);
+ sk = g_io_channel_unix_get_fd(chan);
+ session->sock = sk;
+
+ memset(&l2o, 0, sizeof(l2o));
+ len = sizeof(l2o);
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
+ err = errno;
+ avctp_unref(session);
+ error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err),
+ err);
+ return;
+ }
+
+ init_uinput(session);
+
+ g_dbus_emit_signal(session->dev->conn, session->dev->path,
+ AUDIO_CONTROL_INTERFACE, "Connected",
+ DBUS_TYPE_INVALID);
+
+ session->state = AVCTP_STATE_CONNECTED;
+ session->mtu = l2o.imtu;
+ session->io = g_io_add_watch(chan,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) session_cb, session);
+}
+
+gboolean avrcp_connect(struct audio_device *dev)
+{
+ struct control *control = dev->control;
+ struct avctp *session;
+ int err;
+
+ if (control->session)
+ return TRUE;
+
+ session = avctp_get(&dev->src, &dev->dst);
+ if (!session) {
+ error("Unable to create new AVCTP session");
+ return FALSE;
+ }
+
+ session->dev = dev;
+ session->state = AVCTP_STATE_CONNECTING;
+
+ err = bt_l2cap_connect(&dev->src, &dev->dst, AVCTP_PSM, 0,
+ avctp_connect_cb, session);
+ if (err < 0) {
+ avctp_unref(session);
+ error("Connect failed. %s(%d)", strerror(-err), -err);
+ return FALSE;
+ }
+
+ control->session = session;
+
+ return TRUE;
+}
+
+void avrcp_disconnect(struct audio_device *dev)
+{
+ struct control *control = dev->control;
+ struct avctp *session = control->session;
+
+ if (!session)
+ return;
+
+ avctp_unref(session);
+ control->session = NULL;
+}
+
+int avrcp_init(DBusConnection *conn, GKeyFile *config)
+{
+ sdp_record_t *record;
+ gboolean tmp, master = TRUE;
+ GError *err = NULL;
+
+ if (avctp_server)
+ return 0;
+
+ if (config) {
+ tmp = g_key_file_get_boolean(config, "General",
+ "Master", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ } else
+ master = tmp;
+ }
+
+ connection = dbus_connection_ref(conn);
+
+ record = avrcp_tg_record();
+ if (!record) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ error("Unable to register AVRCP target service record");
+ sdp_record_free(record);
+ return -1;
+ }
+ tg_record_id = record->handle;
+
+ record = avrcp_ct_record();
+ if (!record) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ error("Unable to register AVRCP controller service record");
+ sdp_record_free(record);
+ return -1;
+ }
+ ct_record_id = record->handle;
+
+ avctp_server = avctp_server_socket(master);
+ if (!avctp_server)
+ return -1;
+
+ return 0;
+}
+
+void avrcp_exit(void)
+{
+ if (!avctp_server)
+ return;
+
+ g_io_channel_close(avctp_server);
+ g_io_channel_unref(avctp_server);
+ avctp_server = NULL;
+
+ remove_record_from_server(ct_record_id);
+ ct_record_id = 0;
+
+ remove_record_from_server(tg_record_id);
+ tg_record_id = 0;
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
+
+static DBusMessage *control_is_connected(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct control *control = device->control;
+ DBusMessage *reply;
+ dbus_bool_t connected;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ connected = (control->session != NULL);
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static GDBusMethodTable control_methods[] = {
+ { "IsConnected", "", "b", control_is_connected },
+ { NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable control_signals[] = {
+ { "Connected", "" },
+ { "Disconnected", "" },
+ { NULL, NULL }
+};
+
+struct control *control_init(struct audio_device *dev)
+{
+ if (!g_dbus_register_interface(dev->conn, dev->path,
+ AUDIO_CONTROL_INTERFACE,
+ control_methods, control_signals, NULL,
+ dev, NULL))
+ return NULL;
+
+ return g_new0(struct control, 1);
+}
+
+void control_free(struct audio_device *dev)
+{
+ struct control *control = dev->control;
+
+ if (control->session)
+ avctp_unref(control->session);
+
+ g_free(control);
+ dev->control = NULL;
+}
+
+gboolean control_is_active(struct audio_device *dev)
+{
+ struct control *control = dev->control;
+
+ if (control->session &&
+ control->session->state != AVCTP_STATE_DISCONNECTED)
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/utils/audio/control.h b/utils/audio/control.h
new file mode 100644
index 00000000..bbb5128c
--- /dev/null
+++ b/utils/audio/control.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define AUDIO_CONTROL_INTERFACE "org.bluez.audio.Control"
+
+int avrcp_init(DBusConnection *conn, GKeyFile *config);
+void avrcp_exit(void);
+
+gboolean avrcp_connect(struct audio_device *dev);
+void avrcp_disconnect(struct audio_device *dev);
+
+struct control *control_init(struct audio_device *dev);
+void control_free(struct audio_device *dev);
+gboolean control_is_active(struct audio_device *dev);
diff --git a/utils/audio/ctl_bluetooth.c b/utils/audio/ctl_bluetooth.c
new file mode 100644
index 00000000..a87c3c19
--- /dev/null
+++ b/utils/audio/ctl_bluetooth.c
@@ -0,0 +1,356 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <alsa/asoundlib.h>
+#include <alsa/control_external.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "ipc.h"
+
+#ifdef ENABLE_DEBUG
+#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#else
+#define DBG(fmt, arg...)
+#endif
+
+#define BLUETOOTH_MINVOL 0
+#define BLUETOOTH_MAXVOL 15
+
+struct bluetooth_data {
+ snd_ctl_ext_t ext;
+ int sock;
+};
+
+enum {
+ BLUETOOTH_PLAYBACK,
+ BLUETOOTH_CAPTURE,
+};
+
+static const char *vol_devices[2] = {
+ [BLUETOOTH_PLAYBACK] = "Playback volume",
+ [BLUETOOTH_CAPTURE] = "Capture volume",
+};
+
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+ if (data == NULL)
+ return;
+
+ if (data->sock >= 0)
+ bt_audio_service_close(data->sock);
+
+ free(data);
+}
+
+static void bluetooth_close(snd_ctl_ext_t *ext)
+{
+ struct bluetooth_data *data = ext->private_data;
+
+ DBG("ext %p", ext);
+
+ bluetooth_exit(data);
+}
+
+static int bluetooth_elem_count(snd_ctl_ext_t *ext)
+{
+ DBG("ext %p", ext);
+
+ return 2;
+}
+
+static int bluetooth_elem_list(snd_ctl_ext_t *ext,
+ unsigned int offset, snd_ctl_elem_id_t *id)
+{
+ DBG("ext %p offset %d id %p", ext, offset, id);
+
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+
+ if (offset > 1)
+ return -EINVAL;
+
+ snd_ctl_elem_id_set_name(id, vol_devices[offset]);
+
+ return 0;
+}
+
+static snd_ctl_ext_key_t bluetooth_find_elem(snd_ctl_ext_t *ext,
+ const snd_ctl_elem_id_t *id)
+{
+ const char *name = snd_ctl_elem_id_get_name(id);
+ int i;
+
+ DBG("ext %p id %p name '%s'", ext, id, name);
+
+ for (i = 0; i < 2; i++)
+ if (strcmp(name, vol_devices[i]) == 0)
+ return i;
+
+ return SND_CTL_EXT_KEY_NOT_FOUND;
+}
+
+static int bluetooth_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
+ int *type, unsigned int *acc, unsigned int *count)
+{
+ DBG("ext %p key %ld", ext, key);
+
+ *type = SND_CTL_ELEM_TYPE_INTEGER;
+ *acc = SND_CTL_EXT_ACCESS_READWRITE;
+ *count = 1;
+
+ return 0;
+}
+
+static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
+ long *imin, long *imax, long *istep)
+{
+ DBG("ext %p key %ld", ext, key);
+
+ *istep = 1;
+ *imin = BLUETOOTH_MINVOL;
+ *imax = BLUETOOTH_MAXVOL;
+
+ return 0;
+}
+
+static int bluetooth_send_ctl(struct bluetooth_data *data,
+ uint8_t mode, uint8_t key, struct bt_control_rsp *ctl_rsp)
+{
+ int ret;
+ struct bt_control_req *ctl_req = (void *) ctl_rsp;
+ const char *type;
+
+ memset(ctl_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ ctl_req->h.msg_type = BT_CONTROL_REQ;
+ ctl_req->mode = mode;
+ ctl_req->key = key;
+
+ ret = send(data->sock, ctl_req, BT_AUDIO_IPC_PACKET_SIZE, MSG_NOSIGNAL);
+ if (ret <= 0) {
+ SYSERR("Unable to request new volume value to server");
+ return -errno;
+ }
+
+ ret = recv(data->sock, ctl_rsp, BT_AUDIO_IPC_PACKET_SIZE, 0);
+ if (ret <= 0) {
+ SNDERR("Unable to receive new volume value from server");
+ return -errno;
+ }
+
+ type = bt_audio_strmsg(ctl_rsp->rsp_h.msg_h.msg_type);
+ if (!type) {
+ SNDERR("Bogus message type %d "
+ "received from audio service",
+ ctl_rsp->rsp_h.msg_h.msg_type);
+ return -EINVAL;
+ }
+
+ if (ctl_rsp->rsp_h.msg_h.msg_type != BT_CONTROL_RSP) {
+ SNDERR("Unexpected message %s received", type);
+ return -EINVAL;
+ }
+
+ if (ctl_rsp->rsp_h.posix_errno != 0) {
+ SNDERR("BT_CONTROL failed : %s (%d)",
+ strerror(ctl_rsp->rsp_h.posix_errno),
+ ctl_rsp->rsp_h.posix_errno);
+ return -ctl_rsp->rsp_h.posix_errno;
+ }
+
+ return 0;
+}
+
+static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
+ long *value)
+{
+ struct bluetooth_data *data = ext->private_data;
+ int ret;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_control_rsp *rsp = (void *) buf;
+
+ DBG("ext %p key %ld", ext, key);
+
+ memset(buf, 0, sizeof(buf));
+ *value = 0;
+
+ ret = bluetooth_send_ctl(data, key, 0, rsp);
+ if (ret < 0)
+ goto done;
+
+ *value = rsp->key;
+done:
+ return ret;
+}
+
+static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
+ long *value)
+{
+ struct bluetooth_data *data = ext->private_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_control_rsp *rsp = (void *) buf;
+ long current;
+ int ret, keyvalue;
+
+ DBG("ext %p key %ld", ext, key);
+
+ ret = bluetooth_read_integer(ext, key, &current);
+ if (ret < 0)
+ return ret;
+
+ if (*value == current)
+ return 0;
+
+ while (*value != current) {
+ keyvalue = (*value > current) ? BT_CONTROL_KEY_VOL_UP :
+ BT_CONTROL_KEY_VOL_DOWN;
+
+ ret = bluetooth_send_ctl(data, key, keyvalue, rsp);
+ if (ret < 0)
+ break;
+
+ current = keyvalue;
+ }
+
+ return ret;
+}
+
+static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
+ unsigned int *event_mask)
+{
+ struct bluetooth_data *data = ext->private_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_control_ind *ind = (void *) buf;
+ int ret;
+ const char *type;
+
+ DBG("ext %p id %p", ext, id);
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = recv(data->sock, ind, BT_AUDIO_IPC_PACKET_SIZE, MSG_DONTWAIT);
+ type = bt_audio_strmsg(ind->h.msg_type);
+ if (!type) {
+ SNDERR("Bogus message type %d "
+ "received from audio service",
+ ind->h.msg_type);
+ return -EAGAIN;
+ }
+
+ if (ind->h.msg_type != BT_CONTROL_IND) {
+ SNDERR("Unexpected message %s received", type);
+ return -EAGAIN;
+ }
+
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_id_set_name(id, ind->mode == BLUETOOTH_PLAYBACK ?
+ vol_devices[BLUETOOTH_PLAYBACK] :
+ vol_devices[BLUETOOTH_CAPTURE]);
+ *event_mask = SND_CTL_EVENT_MASK_VALUE;
+
+ return 1;
+}
+
+static snd_ctl_ext_callback_t bluetooth_callback = {
+ .close = bluetooth_close,
+ .elem_count = bluetooth_elem_count,
+ .elem_list = bluetooth_elem_list,
+ .find_elem = bluetooth_find_elem,
+ .get_attribute = bluetooth_get_attribute,
+ .get_integer_info = bluetooth_get_integer_info,
+ .read_integer = bluetooth_read_integer,
+ .write_integer = bluetooth_write_integer,
+ .read_event = bluetooth_read_event,
+};
+
+static int bluetooth_init(struct bluetooth_data *data)
+{
+ int sk;
+
+ if (!data)
+ return -EINVAL;
+
+ memset(data, 0, sizeof(struct bluetooth_data));
+
+ data->sock = -1;
+
+ sk = bt_audio_service_open();
+ if (sk < 0)
+ return -errno;
+
+ data->sock = sk;
+
+ return 0;
+}
+
+SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
+{
+ struct bluetooth_data *data;
+ int err;
+
+ DBG("Bluetooth Control plugin");
+
+ data = malloc(sizeof(struct bluetooth_data));
+ if (!data) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ err = bluetooth_init(data);
+ if (err < 0)
+ goto error;
+
+ data->ext.version = SND_CTL_EXT_VERSION;
+ data->ext.card_idx = -1;
+
+ strncpy(data->ext.id, "bluetooth", sizeof(data->ext.id) - 1);
+ strncpy(data->ext.driver, "Bluetooth-Audio", sizeof(data->ext.driver) - 1);
+ strncpy(data->ext.name, "Bluetooth Audio", sizeof(data->ext.name) - 1);
+ strncpy(data->ext.longname, "Bluetooth Audio", sizeof(data->ext.longname) - 1);
+ strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1);
+
+ data->ext.callback = &bluetooth_callback;
+ data->ext.poll_fd = data->sock;
+ data->ext.private_data = data;
+
+ err = snd_ctl_ext_create(&data->ext, name, mode);
+ if (err < 0)
+ goto error;
+
+ *handlep = data->ext.handle;
+
+ return 0;
+
+error:
+ bluetooth_exit(data);
+
+ return err;
+}
+
+SND_CTL_PLUGIN_SYMBOL(bluetooth);
diff --git a/utils/audio/device.c b/utils/audio/device.c
new file mode 100644
index 00000000..2f5f834f
--- /dev/null
+++ b/utils/audio/device.c
@@ -0,0 +1,435 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "logging.h"
+#include "textfile.h"
+
+#include "error.h"
+#include "ipc.h"
+#include "device.h"
+#include "avdtp.h"
+#include "control.h"
+#include "headset.h"
+#include "sink.h"
+
+static DBusMessage *device_get_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct audio_device *device = data;
+ DBusMessage *reply;
+ char address[18], *ptr = address;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ ba2str(&device->dst, address);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static char *get_dev_name(DBusConnection *conn, const bdaddr_t *src,
+ const bdaddr_t *bda)
+{
+ char address[18], filename[PATH_MAX + 1];
+
+ ba2str(src, address);
+
+ /* check if it is in the cache */
+ create_name(filename, PATH_MAX, STORAGEDIR, address, "names");
+
+ ba2str(bda, address);
+ return textfile_caseget(filename, address);
+}
+
+static DBusMessage *device_get_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct audio_device *dev = data;
+ DBusMessage *reply;
+ const char *name = dev->name ? dev->name : "";
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *device_get_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct audio_device *device = data;
+ DBusMessage *reply;
+ char address[18], *ptr = address;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ ba2str(&device->src, address);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+
+static DBusMessage *device_get_connected(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, array_iter;
+ struct audio_device *device = data;
+ DBusMessage *reply;
+ const char *iface;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING,
+ &array_iter);
+
+ if (device->headset &&
+ headset_get_state(device) >= HEADSET_STATE_CONNECTED) {
+ iface = AUDIO_HEADSET_INTERFACE;
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &iface);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "GetAddress", "", "s", device_get_address },
+ { "GetName", "", "s", device_get_name },
+ { "GetAdapter", "", "s", device_get_adapter },
+ { "GetConnectedInterfaces", "", "as", device_get_connected },
+ { }
+};
+
+static void device_free(struct audio_device *dev)
+{
+ if (dev->headset)
+ headset_free(dev);
+
+ if (dev->sink)
+ sink_free(dev);
+
+ if (dev->control)
+ control_free(dev);
+
+ if (dev->conn)
+ dbus_connection_unref(dev->conn);
+
+ g_free(dev->adapter_path);
+ g_free(dev->path);
+ g_free(dev->name);
+
+ g_free(dev);
+}
+
+static void device_unregister(void *data)
+{
+ struct audio_device *device = data;
+
+ info("Unregistered device path:%s", device->path);
+
+ device_free(device);
+}
+
+struct audio_device *device_register(DBusConnection *conn,
+ const char *path, const bdaddr_t *bda)
+{
+ struct audio_device *dev;
+ bdaddr_t src;
+ int dev_id;
+
+ if (!conn || !path)
+ return NULL;
+
+ bacpy(&src, BDADDR_ANY);
+ dev_id = hci_get_route(&src);
+ if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
+ return NULL;
+
+ dev = g_new0(struct audio_device, 1);
+
+ /* FIXME just to maintain compatibility */
+ dev->adapter_path = g_strdup_printf("/org/bluez/hci%d", dev_id);
+ if (!dev->adapter_path) {
+ device_free(dev);
+ return NULL;
+ }
+
+ if (!g_dbus_register_interface(conn, path,
+ AUDIO_DEVICE_INTERFACE,
+ device_methods, NULL, NULL,
+ dev, device_unregister)) {
+ error("Failed to register %s interface to %s",
+ AUDIO_DEVICE_INTERFACE, path);
+ device_free(dev);
+ return NULL;
+ }
+
+ dev->name = get_dev_name(conn, &src, bda);
+ dev->path = g_strdup(path);
+ bacpy(&dev->dst, bda);
+ bacpy(&dev->src, &src);
+ bacpy(&dev->store, &src);
+ dev->conn = dbus_connection_ref(conn);
+
+ return dev;
+}
+
+int device_store(struct audio_device *dev, gboolean is_default)
+{
+ char value[64];
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ int offset = 0;
+
+ if (!dev->path)
+ return -EINVAL;
+
+ ba2str(&dev->dst, dst_addr);
+ ba2str(&dev->store, src_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (is_default)
+ textfile_put(filename, "default", dst_addr);
+ if (dev->headset) {
+ snprintf(value, 64, "headset ");
+ offset += strlen("headset ");
+ }
+ if (dev->gateway) {
+ snprintf(value + offset, 64 - offset, "gateway ");
+ offset += strlen("gateway ");
+ }
+ if (dev->sink) {
+ snprintf(value + offset, 64 - offset, "sink ");
+ offset += strlen("sink ");
+ }
+ if (dev->source) {
+ snprintf(value + offset, 64 - offset, "source ");
+ offset += strlen("source ");
+ }
+ if (dev->control) {
+ snprintf(value + offset, 64 - offset, "control ");
+ offset += strlen("control ");
+ }
+ if (dev->target)
+ snprintf(value + offset, 64 - offset, "target");
+
+ return textfile_put(filename, dst_addr, value);
+}
+
+int device_remove_stored(struct audio_device *dev)
+{
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+
+ ba2str(&dev->dst, dst_addr);
+ ba2str(&dev->store, src_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
+
+ return textfile_del(filename, dst_addr);
+}
+
+void device_finish_sdp_transaction(struct audio_device *dev)
+{
+ char address[18], *addr_ptr = address;
+ DBusMessage *msg;
+
+ ba2str(&dev->dst, address);
+
+ msg = dbus_message_new_method_call("org.bluez", dev->adapter_path,
+ "org.bluez.Adapter",
+ "FinishRemoteServiceTransaction");
+ if (!msg) {
+ error("Unable to allocate new method call");
+ return;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(dev->conn, msg, NULL);
+
+ dbus_message_unref(msg);
+}
+
+#if 0
+static avdtp_state_t ipc_to_avdtp_state(uint8_t ipc_state)
+{
+ switch (ipc_state) {
+ case STATE_DISCONNECTED:
+ return AVDTP_STATE_IDLE;
+ case STATE_CONNECTING:
+ return AVDTP_STATE_CONFIGURED;
+ case STATE_CONNECTED:
+ return AVDTP_STATE_OPEN;
+ case STATE_STREAM_STARTING:
+ case STATE_STREAMING:
+ return AVDTP_STATE_STREAMING;
+ default:
+ error("Unknown ipc state");
+ return AVDTP_STATE_IDLE;
+ }
+}
+
+static headset_state_t ipc_to_hs_state(uint8_t ipc_state)
+{
+ switch (ipc_state) {
+ case STATE_DISCONNECTED:
+ return HEADSET_STATE_DISCONNECTED;
+ case STATE_CONNECTING:
+ return HEADSET_STATE_CONNECT_IN_PROGRESS;
+ case STATE_CONNECTED:
+ return HEADSET_STATE_CONNECTED;
+ case STATE_STREAM_STARTING:
+ return HEADSET_STATE_PLAY_IN_PROGRESS;
+ case STATE_STREAMING:
+ return HEADSET_STATE_PLAYING;
+ default:
+ error("Unknown ipc state");
+ return HEADSET_STATE_DISCONNECTED;
+ }
+}
+
+static uint8_t avdtp_to_ipc_state(avdtp_state_t state)
+{
+ switch (state) {
+ case AVDTP_STATE_IDLE:
+ return STATE_DISCONNECTED;
+ case AVDTP_STATE_CONFIGURED:
+ return STATE_CONNECTING;
+ case AVDTP_STATE_OPEN:
+ return STATE_CONNECTED;
+ case AVDTP_STATE_STREAMING:
+ return STATE_STREAMING;
+ default:
+ error("Unknown avdt state");
+ return AVDTP_STATE_IDLE;
+ }
+}
+
+static uint8_t hs_to_ipc_state(headset_state_t state)
+{
+ switch (state) {
+ case HEADSET_STATE_DISCONNECTED:
+ return STATE_DISCONNECTED;
+ case HEADSET_STATE_CONNECT_IN_PROGRESS:
+ return STATE_CONNECTING;
+ case HEADSET_STATE_CONNECTED:
+ return STATE_CONNECTED;
+ case HEADSET_STATE_PLAY_IN_PROGRESS:
+ return STATE_STREAMING;
+ default:
+ error("Unknown headset state");
+ return AVDTP_STATE_IDLE;
+ }
+}
+
+uint8_t device_get_state(struct audio_device *dev)
+{
+ avdtp_state_t sink_state;
+ headset_state_t hs_state;
+
+ if (dev->sink && sink_is_active(dev)) {
+ sink_state = sink_get_state(dev);
+ return avdtp_to_ipc_state(sink_state);
+ }
+ else if (dev->headset && headset_is_active(dev)) {
+ hs_state = headset_get_state(dev);
+ return hs_to_ipc_state(hs_state);
+ }
+ else if (dev->control && control_is_active(dev))
+ return STATE_CONNECTED;
+
+ return STATE_DISCONNECTED;
+}
+#endif
+
+gboolean device_is_connected(struct audio_device *dev, const char *interface)
+{
+ if (!interface) {
+ if ((dev->sink || dev->source) &&
+ avdtp_is_connected(&dev->src, &dev->dst))
+ return TRUE;
+
+ if (dev->headset && headset_is_active(dev))
+ return TRUE;
+ }
+ else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&
+ avdtp_is_connected(&dev->src, &dev->dst))
+ return TRUE;
+ else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source &&
+ avdtp_is_connected(&dev->src, &dev->dst))
+ return TRUE;
+ else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
+ headset_is_active(dev))
+ return TRUE;
+ else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->headset &&
+ control_is_active(dev))
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/utils/audio/device.h b/utils/audio/device.h
new file mode 100644
index 00000000..5dc99b9d
--- /dev/null
+++ b/utils/audio/device.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define AUDIO_DEVICE_INTERFACE "org.bluez.audio.Device"
+
+#define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805F9B34FB"
+
+#define HSP_HS_UUID "00001108-0000-1000-8000-00805F9B34FB"
+#define HSP_AG_UUID "00001112-0000-1000-8000-00805F9B34FB"
+
+#define HFP_HS_UUID "0000111E-0000-1000-8000-00805F9B34FB"
+#define HFP_AG_UUID "0000111F-0000-1000-8000-00805F9B34FB"
+
+#define ADVANCED_AUDIO_UUID "0000110D-0000-1000-8000-00805F9B34FB"
+
+#define A2DP_SOURCE_UUID "0000110A-0000-1000-8000-00805F9B34FB"
+#define A2DP_SINK_UUID "0000110B-0000-1000-8000-00805F9B34FB"
+
+#define AVRCP_REMOTE_UUID "0000110E-0000-1000-8000-00805F9B34FB"
+#define AVRCP_TARGET_UUID "0000110C-0000-1000-8000-00805F9B34FB"
+
+/* Move these to respective .h files once they exist */
+#define AUDIO_SOURCE_INTERFACE "org.bluez.audio.Source"
+#define AUDIO_CONTROL_INTERFACE "org.bluez.audio.Control"
+#define AUDIO_TARGET_INTERFACE "org.bluez.audio.Target"
+
+struct source;
+struct control;
+struct target;
+struct sink;
+struct headset;
+struct gateway;
+
+struct audio_device {
+ DBusConnection *conn;
+ char *adapter_path;
+ char *path;
+ char *name;
+ bdaddr_t store;
+ bdaddr_t src;
+ bdaddr_t dst;
+
+ struct headset *headset;
+ struct gateway *gateway;
+ struct sink *sink;
+ struct source *source;
+ struct control *control;
+ struct target *target;
+};
+
+struct audio_device *device_register(DBusConnection *conn,
+ const char *path, const bdaddr_t *bda);
+
+int device_store(struct audio_device *device, gboolean is_default);
+
+int device_remove_stored(struct audio_device *dev);
+
+void device_finish_sdp_transaction(struct audio_device *device);
+
+uint8_t device_get_state(struct audio_device *dev);
+
+gboolean device_is_connected(struct audio_device *dev, const char *interface);
diff --git a/utils/audio/gateway.c b/utils/audio/gateway.c
new file mode 100644
index 00000000..a299d28a
--- /dev/null
+++ b/utils/audio/gateway.c
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gateway.h"
diff --git a/utils/audio/gateway.h b/utils/audio/gateway.h
new file mode 100644
index 00000000..12e413fd
--- /dev/null
+++ b/utils/audio/gateway.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define AUDIO_GATEWAY_INTERFACE "org.bluez.audio.Gateway"
+
+#define DEFAULT_HSP_HS_CHANNEL 6
+#define DEFAULT_HFP_HS_CHANNEL 7
+
+int gateway_init(DBusConnection *conn, gboolean disable_hfp, gboolean sco_hci);
+
+void gateway_exit(void);
+
+gboolean gateway_is_enabled(uint16_t svc);
diff --git a/utils/audio/gsta2dpsink.c b/utils/audio/gsta2dpsink.c
new file mode 100644
index 00000000..d25cbded
--- /dev/null
+++ b/utils/audio/gsta2dpsink.c
@@ -0,0 +1,701 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <pthread.h>
+
+#include "gsta2dpsink.h"
+
+GST_DEBUG_CATEGORY_STATIC(gst_a2dp_sink_debug);
+#define GST_CAT_DEFAULT gst_a2dp_sink_debug
+
+#define A2DP_SBC_RTP_PAYLOAD_TYPE 1
+#define TEMPLATE_MAX_BITPOOL_STR "64"
+
+#define DEFAULT_AUTOCONNECT TRUE
+
+enum {
+ PROP_0,
+ PROP_DEVICE,
+ PROP_AUTOCONNECT
+};
+
+GST_BOILERPLATE(GstA2dpSink, gst_a2dp_sink, GstBin, GST_TYPE_BIN);
+
+static const GstElementDetails gst_a2dp_sink_details =
+ GST_ELEMENT_DETAILS("Bluetooth A2DP sink",
+ "Sink/Audio",
+ "Plays audio to an A2DP device",
+ "Marcel Holtmann <marcel@holtmann.org>");
+
+static GstStaticPadTemplate gst_a2dp_sink_factory =
+ GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-sbc, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
+ "blocks = (int) { 4, 8, 12, 16 }, "
+ "subbands = (int) { 4, 8 }, "
+ "allocation = (string) { \"snr\", \"loudness\" }, "
+ "bitpool = (int) [ 2, "
+ TEMPLATE_MAX_BITPOOL_STR " ]; "
+ "audio/mpeg"
+ ));
+
+static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event);
+static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps);
+static GstCaps *gst_a2dp_sink_get_caps(GstPad *pad);
+static gboolean gst_a2dp_sink_init_caps_filter(GstA2dpSink *self);
+static gboolean gst_a2dp_sink_init_fakesink(GstA2dpSink *self);
+static gboolean gst_a2dp_sink_remove_fakesink(GstA2dpSink *self);
+
+static void gst_a2dp_sink_finalize(GObject *obj)
+{
+ GstA2dpSink *self = GST_A2DP_SINK(obj);
+
+ g_mutex_free(self->cb_mutex);
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static GstState gst_a2dp_sink_get_state(GstA2dpSink *self)
+{
+ GstState current, pending;
+
+ gst_element_get_state(GST_ELEMENT(self), &current, &pending, 0);
+ if (pending == GST_STATE_VOID_PENDING)
+ return current;
+
+ return pending;
+}
+
+/*
+ * Helper function to create elements, add to the bin and link it
+ * to another element.
+ */
+static GstElement* gst_a2dp_sink_init_element(GstA2dpSink *self,
+ const gchar* elementname, const gchar* name,
+ GstElement *link_to)
+{
+ GstElement *element;
+ GstState state;
+
+ GST_LOG_OBJECT(self, "Initializing %s", elementname);
+
+ element = gst_element_factory_make(elementname, name);
+ if (element == NULL) {
+ GST_DEBUG_OBJECT(self, "Couldn't create %s", elementname);
+ return NULL;
+ }
+
+ if (!gst_bin_add(GST_BIN(self), element)) {
+ GST_DEBUG_OBJECT(self, "failed to add %s to the bin",
+ elementname);
+ goto cleanup_and_fail;
+ }
+
+ state = gst_a2dp_sink_get_state(self);
+ if (gst_element_set_state(element, state) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_DEBUG_OBJECT(self, "%s failed to go to playing",
+ elementname);
+ goto remove_element_and_fail;
+ }
+
+ if (link_to != NULL)
+ if (!gst_element_link(link_to, element)) {
+ GST_DEBUG_OBJECT(self, "couldn't link %s",
+ elementname);
+ goto remove_element_and_fail;
+ }
+
+ return element;
+
+remove_element_and_fail:
+ gst_element_set_state(element, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(self), element);
+ return NULL;
+
+cleanup_and_fail:
+ if (element != NULL)
+ g_object_unref(G_OBJECT(element));
+
+ return NULL;
+}
+
+static void gst_a2dp_sink_base_init(gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_set_details(element_class,
+ &gst_a2dp_sink_details);
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&gst_a2dp_sink_factory));
+}
+
+static void gst_a2dp_sink_set_property(GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GstA2dpSink *self = GST_A2DP_SINK(object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ if (self->sink != NULL)
+ gst_avdtp_sink_set_device(self->sink,
+ g_value_get_string(value));
+
+ if (self->device != NULL)
+ g_free(self->device);
+ self->device = g_value_dup_string(value);
+ break;
+
+ case PROP_AUTOCONNECT:
+ self->autoconnect = g_value_get_boolean(value);
+
+ if (self->sink != NULL)
+ g_object_set(G_OBJECT(self->sink), "auto-connect",
+ self->autoconnect, NULL);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gst_a2dp_sink_get_property(GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GstA2dpSink *self = GST_A2DP_SINK(object);
+ gchar *device;
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ if (self->sink != NULL) {
+ device = gst_avdtp_sink_get_device(self->sink);
+ if (device != NULL)
+ g_value_take_string(value, device);
+ }
+ break;
+ case PROP_AUTOCONNECT:
+ if (self->sink != NULL)
+ g_object_get(G_OBJECT(self->sink), "auto-connect",
+ &self->autoconnect, NULL);
+
+ g_value_set_boolean(value, self->autoconnect);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean gst_a2dp_sink_init_ghost_pad(GstA2dpSink *self)
+{
+ GstPad *capsfilter_pad;
+
+ /* we search for the capsfilter sinkpad */
+ capsfilter_pad = gst_element_get_static_pad(self->capsfilter, "sink");
+
+ /* now we add a ghostpad */
+ self->ghostpad = GST_GHOST_PAD(gst_ghost_pad_new("sink",
+ capsfilter_pad));
+ g_object_unref(capsfilter_pad);
+
+ /* the getcaps of our ghostpad must reflect the device caps */
+ gst_pad_set_getcaps_function(GST_PAD(self->ghostpad),
+ gst_a2dp_sink_get_caps);
+ self->ghostpad_setcapsfunc = GST_PAD_SETCAPSFUNC(self->ghostpad);
+ gst_pad_set_setcaps_function(GST_PAD(self->ghostpad),
+ GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_caps));
+
+ /* we need to handle events on our own and we also need the eventfunc
+ * of the ghostpad for forwarding calls */
+ self->ghostpad_eventfunc = GST_PAD_EVENTFUNC(GST_PAD(self->ghostpad));
+ gst_pad_set_event_function(GST_PAD(self->ghostpad),
+ gst_a2dp_sink_handle_event);
+
+ if (!gst_element_add_pad(GST_ELEMENT(self), GST_PAD(self->ghostpad)))
+ GST_ERROR_OBJECT(self, "failed to add ghostpad");
+
+ return TRUE;
+}
+
+static void gst_a2dp_sink_remove_dynamic_elements(GstA2dpSink *self)
+{
+ if (self->rtp) {
+ GST_LOG_OBJECT(self, "removing rtp element from the bin");
+ if (!gst_bin_remove(GST_BIN(self), GST_ELEMENT(self->rtp)))
+ GST_WARNING_OBJECT(self, "failed to remove rtp "
+ "element from bin");
+ else
+ self->rtp = NULL;
+ }
+}
+
+static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstA2dpSink *self = GST_A2DP_SINK(element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ self->taglist = gst_tag_list_new();
+
+ gst_a2dp_sink_init_fakesink(self);
+ break;
+
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ self->sink_is_in_bin = FALSE;
+ self->sink = GST_AVDTP_SINK(gst_element_factory_make(
+ "avdtpsink", "avdtpsink"));
+ if (self->sink == NULL) {
+ GST_WARNING_OBJECT(self, "failed to create avdtpsink");
+ return GST_STATE_CHANGE_FAILURE;
+ }
+
+ if (self->device != NULL)
+ gst_avdtp_sink_set_device(self->sink,
+ self->device);
+
+ g_object_set(G_OBJECT(self->sink), "auto-connect",
+ self->autoconnect, NULL);
+
+ ret = gst_element_set_state(GST_ELEMENT(self->sink),
+ GST_STATE_READY);
+ break;
+ default:
+ break;
+ }
+
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ ret = GST_ELEMENT_CLASS(parent_class)->change_state(element,
+ transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ if (self->taglist) {
+ gst_tag_list_free(self->taglist);
+ self->taglist = NULL;
+ }
+ if (self->newseg_event != NULL) {
+ gst_event_unref(self->newseg_event);
+ self->newseg_event = NULL;
+ }
+ gst_a2dp_sink_remove_fakesink(self);
+ break;
+
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (self->sink_is_in_bin) {
+ if (!gst_bin_remove(GST_BIN(self),
+ GST_ELEMENT(self->sink)))
+ GST_WARNING_OBJECT(self, "Failed to remove "
+ "avdtpsink from bin");
+ } else if (self->sink != NULL) {
+ gst_element_set_state(GST_ELEMENT(self->sink),
+ GST_STATE_NULL);
+ g_object_unref(G_OBJECT(self->sink));
+ }
+
+ self->sink = NULL;
+
+ gst_a2dp_sink_remove_dynamic_elements(self);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ object_class->set_property = GST_DEBUG_FUNCPTR(
+ gst_a2dp_sink_set_property);
+ object_class->get_property = GST_DEBUG_FUNCPTR(
+ gst_a2dp_sink_get_property);
+
+ object_class->finalize = GST_DEBUG_FUNCPTR(
+ gst_a2dp_sink_finalize);
+
+ element_class->change_state = GST_DEBUG_FUNCPTR(
+ gst_a2dp_sink_change_state);
+
+ g_object_class_install_property(object_class, PROP_DEVICE,
+ g_param_spec_string("device", "Device",
+ "Bluetooth remote device address",
+ NULL, G_PARAM_READWRITE));
+
+ g_object_class_install_property(object_class, PROP_AUTOCONNECT,
+ g_param_spec_boolean("auto-connect", "Auto-connect",
+ "Automatically attempt to connect to device",
+ DEFAULT_AUTOCONNECT, G_PARAM_READWRITE));
+
+ GST_DEBUG_CATEGORY_INIT(gst_a2dp_sink_debug, "a2dpsink", 0,
+ "A2DP sink element");
+}
+
+GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self)
+{
+ return gst_avdtp_sink_get_device_caps(self->sink);
+}
+
+static GstCaps *gst_a2dp_sink_get_caps(GstPad *pad)
+{
+ GstCaps *caps;
+ GstCaps *caps_aux;
+ GstA2dpSink *self = GST_A2DP_SINK(GST_PAD_PARENT(pad));
+
+ if (self->sink == NULL) {
+ GST_DEBUG_OBJECT(self, "a2dpsink isn't initialized "
+ "returning template caps");
+ caps = gst_static_pad_template_get_caps(
+ &gst_a2dp_sink_factory);
+ } else {
+ GST_LOG_OBJECT(self, "Getting device caps");
+ caps = gst_a2dp_sink_get_device_caps(self);
+ if (caps == NULL)
+ caps = gst_static_pad_template_get_caps(
+ &gst_a2dp_sink_factory);
+ }
+ caps_aux = gst_caps_copy(caps);
+ g_object_set(self->capsfilter, "caps", caps_aux, NULL);
+ gst_caps_unref(caps_aux);
+ return caps;
+}
+
+static gboolean gst_a2dp_sink_init_avdtp_sink(GstA2dpSink *self)
+{
+ GstElement *sink;
+
+ /* check if we don't need a new sink */
+ if (self->sink_is_in_bin)
+ return TRUE;
+
+ if (self->sink == NULL)
+ sink = gst_element_factory_make("avdtpsink", "avdtpsink");
+ else
+ sink = GST_ELEMENT(self->sink);
+
+ if (sink == NULL) {
+ GST_ERROR_OBJECT(self, "Couldn't create avdtpsink");
+ return FALSE;
+ }
+
+ if (!gst_bin_add(GST_BIN(self), sink)) {
+ GST_ERROR_OBJECT(self, "failed to add avdtpsink "
+ "to the bin");
+ goto cleanup_and_fail;
+ }
+
+ if (gst_element_set_state(sink, GST_STATE_READY) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_ERROR_OBJECT(self, "avdtpsink failed to go to ready");
+ goto remove_element_and_fail;
+ }
+
+ if (!gst_element_link(GST_ELEMENT(self->rtp), sink)) {
+ GST_ERROR_OBJECT(self, "couldn't link rtpsbcpay "
+ "to avdtpsink");
+ goto remove_element_and_fail;
+ }
+
+ self->sink = GST_AVDTP_SINK(sink);
+ self->sink_is_in_bin = TRUE;
+ g_object_set(G_OBJECT(self->sink), "device", self->device, NULL);
+
+ gst_element_set_state(sink, GST_STATE_PAUSED);
+
+ return TRUE;
+
+remove_element_and_fail:
+ gst_element_set_state (sink, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(self), sink);
+ return FALSE;
+
+cleanup_and_fail:
+ if (sink != NULL)
+ g_object_unref(G_OBJECT(sink));
+
+ return FALSE;
+}
+
+static gboolean gst_a2dp_sink_init_rtp_sbc_element(GstA2dpSink *self)
+{
+ GstElement *rtppay;
+
+ /* if we already have a rtp, we don't need a new one */
+ if (self->rtp != NULL)
+ return TRUE;
+
+ rtppay = gst_a2dp_sink_init_element(self, "rtpsbcpay", "rtp",
+ self->capsfilter);
+ if (rtppay == NULL)
+ return FALSE;
+
+ self->rtp = GST_BASE_RTP_PAYLOAD(rtppay);
+ g_object_set(G_OBJECT(self->rtp), "min-frames", -1, NULL);
+
+ gst_element_set_state(rtppay, GST_STATE_PAUSED);
+
+ return TRUE;
+}
+
+static gboolean gst_a2dp_sink_init_rtp_mpeg_element(GstA2dpSink *self)
+{
+ GstElement *rtppay;
+
+ /* check if we don't need a new rtp */
+ if (self->rtp)
+ return TRUE;
+
+ GST_LOG_OBJECT(self, "Initializing rtp mpeg element");
+ /* if capsfilter is not created then we can't have our rtp element */
+ if (self->capsfilter == NULL)
+ return FALSE;
+
+ rtppay = gst_a2dp_sink_init_element(self, "rtpmpapay", "rtp",
+ self->capsfilter);
+ if (rtppay == NULL)
+ return FALSE;
+
+ self->rtp = GST_BASE_RTP_PAYLOAD(rtppay);
+
+ gst_element_set_state(rtppay, GST_STATE_PAUSED);
+
+ return TRUE;
+}
+
+static gboolean gst_a2dp_sink_init_dynamic_elements(GstA2dpSink *self,
+ GstCaps *caps)
+{
+ GstStructure *structure;
+ GstEvent *event;
+ GstPad *capsfilterpad;
+ gboolean crc;
+ gchar *mode = NULL;
+
+ structure = gst_caps_get_structure(caps, 0);
+
+ /* before everything we need to remove fakesink */
+ gst_a2dp_sink_remove_fakesink(self);
+
+ /* first, we need to create our rtp payloader */
+ if (gst_structure_has_name(structure, "audio/x-sbc")) {
+ GST_LOG_OBJECT(self, "sbc media received");
+ if (!gst_a2dp_sink_init_rtp_sbc_element(self))
+ return FALSE;
+ } else if (gst_structure_has_name(structure, "audio/mpeg")) {
+ GST_LOG_OBJECT(self, "mp3 media received");
+ if (!gst_a2dp_sink_init_rtp_mpeg_element(self))
+ return FALSE;
+ } else {
+ GST_ERROR_OBJECT(self, "Unexpected media type");
+ return FALSE;
+ }
+
+ if (!gst_a2dp_sink_init_avdtp_sink(self))
+ return FALSE;
+
+ /* check if we should push the taglist FIXME should we push this?
+ * we can send the tags directly if needed */
+ if (self->taglist != NULL &&
+ gst_structure_has_name(structure, "audio/mpeg")) {
+
+ event = gst_event_new_tag(self->taglist);
+
+ /* send directly the crc */
+ if (gst_tag_list_get_boolean(self->taglist, "has-crc", &crc))
+ gst_avdtp_sink_set_crc(self->sink, crc);
+
+ if (gst_tag_list_get_string(self->taglist, "channel-mode",
+ &mode))
+ gst_avdtp_sink_set_channel_mode(self->sink, mode);
+
+ capsfilterpad = gst_ghost_pad_get_target(self->ghostpad);
+ gst_pad_send_event(capsfilterpad, event);
+ self->taglist = NULL;
+ g_free(mode);
+ }
+
+ if (!gst_avdtp_sink_set_device_caps(self->sink, caps))
+ return FALSE;
+
+ g_object_set(G_OBJECT(self->rtp), "mtu",
+ gst_avdtp_sink_get_link_mtu(self->sink), NULL);
+
+ /* we forward our new segment here if we have one */
+ if (self->newseg_event) {
+ gst_pad_send_event(GST_BASE_RTP_PAYLOAD_SINKPAD(self->rtp),
+ self->newseg_event);
+ self->newseg_event = NULL;
+ }
+
+ return TRUE;
+}
+
+static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps)
+{
+ GstA2dpSink *self;
+
+ self = GST_A2DP_SINK(GST_PAD_PARENT(pad));
+ GST_INFO_OBJECT(self, "setting caps");
+
+ /* now we know the caps */
+ gst_a2dp_sink_init_dynamic_elements(self, caps);
+
+ return self->ghostpad_setcapsfunc(GST_PAD(self->ghostpad), caps);
+}
+
+/* used for catching newsegment events while we don't have a sink, for
+ * later forwarding it to the sink */
+static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event)
+{
+ GstA2dpSink *self;
+ GstTagList *taglist = NULL;
+ GstObject *parent;
+
+ self = GST_A2DP_SINK(GST_PAD_PARENT(pad));
+ parent = gst_element_get_parent(GST_ELEMENT(self->sink));
+
+ if (GST_EVENT_TYPE(event) == GST_EVENT_NEWSEGMENT &&
+ parent != GST_OBJECT_CAST(self)) {
+ if (self->newseg_event != NULL)
+ gst_event_unref(self->newseg_event);
+ self->newseg_event = gst_event_ref(event);
+
+ } else if (GST_EVENT_TYPE(event) == GST_EVENT_TAG &&
+ parent != GST_OBJECT_CAST(self)) {
+ if (self->taglist == NULL)
+ gst_event_parse_tag(event, &self->taglist);
+ else {
+ gst_event_parse_tag(event, &taglist);
+ gst_tag_list_insert(self->taglist, taglist,
+ GST_TAG_MERGE_REPLACE);
+ }
+ }
+
+ if (parent != NULL)
+ gst_object_unref(GST_OBJECT(parent));
+
+ return self->ghostpad_eventfunc(GST_PAD(self->ghostpad), event);
+}
+
+static gboolean gst_a2dp_sink_init_caps_filter(GstA2dpSink *self)
+{
+ GstElement *element;
+
+ element = gst_element_factory_make("capsfilter", "filter");
+ if (element == NULL)
+ goto failed;
+
+ if (!gst_bin_add(GST_BIN(self), element))
+ goto failed;
+
+ self->capsfilter = element;
+ return TRUE;
+
+failed:
+ GST_ERROR_OBJECT(self, "Failed to initialize caps filter");
+ return FALSE;
+}
+
+static gboolean gst_a2dp_sink_init_fakesink(GstA2dpSink *self)
+{
+ if (self->fakesink != NULL)
+ return TRUE;
+
+ g_mutex_lock (self->cb_mutex);
+ self->fakesink = gst_a2dp_sink_init_element(self, "fakesink",
+ "fakesink", self->capsfilter);
+ g_mutex_unlock (self->cb_mutex);
+
+ if (!self->fakesink)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean gst_a2dp_sink_remove_fakesink(GstA2dpSink *self)
+{
+ g_mutex_lock(self->cb_mutex);
+
+ if (self->fakesink != NULL) {
+ gst_element_set_locked_state(self->fakesink, TRUE);
+ gst_element_set_state(self->fakesink, GST_STATE_NULL);
+
+ gst_bin_remove(GST_BIN(self), self->fakesink);
+ self->fakesink = NULL;
+ }
+
+ g_mutex_unlock(self->cb_mutex);
+
+ return TRUE;
+}
+
+static void gst_a2dp_sink_init(GstA2dpSink *self,
+ GstA2dpSinkClass *klass)
+{
+ self->sink = NULL;
+ self->fakesink = NULL;
+ self->rtp = NULL;
+ self->device = NULL;
+ self->autoconnect = DEFAULT_AUTOCONNECT;
+ self->capsfilter = NULL;
+ self->newseg_event = NULL;
+ self->taglist = NULL;
+ self->ghostpad = NULL;
+ self->sink_is_in_bin = FALSE;
+
+ self->cb_mutex = g_mutex_new();
+
+ /* we initialize our capsfilter */
+ gst_a2dp_sink_init_caps_filter(self);
+ g_object_set(self->capsfilter, "caps",
+ gst_static_pad_template_get_caps(&gst_a2dp_sink_factory),
+ NULL);
+
+ gst_a2dp_sink_init_fakesink(self);
+
+ gst_a2dp_sink_init_ghost_pad(self);
+
+}
+
+gboolean gst_a2dp_sink_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "a2dpsink",
+ GST_RANK_PRIMARY, GST_TYPE_A2DP_SINK);
+}
+
diff --git a/utils/audio/gsta2dpsink.h b/utils/audio/gsta2dpsink.h
new file mode 100644
index 00000000..13409232
--- /dev/null
+++ b/utils/audio/gsta2dpsink.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gst/gst.h>
+#include <gst/rtp/gstbasertppayload.h>
+#include "gstavdtpsink.h"
+
+#ifndef __GST_A2DP_SINK_H__
+#define __GST_A2DP_SINK_H__
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_A2DP_SINK \
+ (gst_a2dp_sink_get_type())
+#define GST_A2DP_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_A2DP_SINK,GstA2dpSink))
+#define GST_A2DP_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_A2DP_SINK,GstA2dpSinkClass))
+#define GST_IS_A2DP_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_A2DP_SINK))
+#define GST_IS_A2DP_SINK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_A2DP_SINK))
+
+typedef struct _GstA2dpSink GstA2dpSink;
+typedef struct _GstA2dpSinkClass GstA2dpSinkClass;
+
+struct _GstA2dpSink {
+ GstBin bin;
+
+ GstBaseRTPPayload *rtp;
+ GstAvdtpSink *sink;
+ GstElement *capsfilter;
+ GstElement *fakesink;
+
+ gchar *device;
+ gboolean autoconnect;
+ gboolean sink_is_in_bin;
+
+ GstGhostPad *ghostpad;
+ GstPadSetCapsFunction ghostpad_setcapsfunc;
+ GstPadEventFunction ghostpad_eventfunc;
+
+ GstEvent *newseg_event;
+ /* Store the tags received before the a2dpsender sink is created
+ * when it is created we forward this to it */
+ GstTagList *taglist;
+
+ GMutex *cb_mutex;
+};
+
+struct _GstA2dpSinkClass {
+ GstBinClass parent_class;
+};
+
+GType gst_a2dp_sink_get_type(void);
+gboolean gst_a2dp_sink_plugin_init (GstPlugin * plugin);
+
+GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self);
+
+G_END_DECLS
+
+#endif
+
diff --git a/utils/audio/gstavdtpsink.c b/utils/audio/gstavdtpsink.c
new file mode 100644
index 00000000..4c453ae9
--- /dev/null
+++ b/utils/audio/gstavdtpsink.c
@@ -0,0 +1,1361 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "ipc.h"
+#include "rtp.h"
+
+#include "gstavdtpsink.h"
+
+GST_DEBUG_CATEGORY_STATIC(avdtp_sink_debug);
+#define GST_CAT_DEFAULT avdtp_sink_debug
+
+#define BUFFER_SIZE 2048
+#define TEMPLATE_MAX_BITPOOL 64
+#define CRC_PROTECTED 1
+#define CRC_UNPROTECTED 0
+
+#define DEFAULT_AUTOCONNECT TRUE
+
+#define GST_AVDTP_SINK_MUTEX_LOCK(s) G_STMT_START { \
+ g_mutex_lock (s->sink_lock); \
+ } G_STMT_END
+
+#define GST_AVDTP_SINK_MUTEX_UNLOCK(s) G_STMT_START { \
+ g_mutex_unlock (s->sink_lock); \
+ } G_STMT_END
+
+
+struct bluetooth_data {
+ struct bt_getcapabilities_rsp caps; /* Bluetooth device caps */
+ guint link_mtu;
+
+ gchar buffer[BUFFER_SIZE]; /* Codec transfer buffer */
+};
+
+#define IS_SBC(n) (strcmp((n), "audio/x-sbc") == 0)
+#define IS_MPEG_AUDIO(n) (strcmp((n), "audio/mpeg") == 0)
+
+enum {
+ PROP_0,
+ PROP_DEVICE,
+ PROP_AUTOCONNECT
+};
+
+GST_BOILERPLATE(GstAvdtpSink, gst_avdtp_sink, GstBaseSink,
+ GST_TYPE_BASE_SINK);
+
+static const GstElementDetails avdtp_sink_details =
+ GST_ELEMENT_DETAILS("Bluetooth AVDTP sink",
+ "Sink/Audio",
+ "Plays audio to an A2DP device",
+ "Marcel Holtmann <marcel@holtmann.org>");
+
+static GstStaticPadTemplate avdtp_sink_factory =
+ GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("application/x-rtp, "
+ "media = (string) \"audio\","
+ "payload = (int) "
+ GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 16000, 32000, "
+ "44100, 48000 }, "
+ "encoding-name = (string) \"SBC\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) "
+ GST_RTP_PAYLOAD_MPA_STRING ", "
+ "clock-rate = (int) 90000; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) "
+ GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, "
+ "encoding-name = (string) \"MPA\""
+ ));
+
+static GIOError gst_avdtp_sink_audioservice_send(GstAvdtpSink *self,
+ const bt_audio_msg_header_t *msg);
+static GIOError gst_avdtp_sink_audioservice_expect(
+ GstAvdtpSink *self,
+ bt_audio_msg_header_t *outmsg,
+ int expected_type);
+
+
+static void gst_avdtp_sink_base_init(gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&avdtp_sink_factory));
+
+ gst_element_class_set_details(element_class, &avdtp_sink_details);
+}
+
+static gboolean gst_avdtp_sink_stop(GstBaseSink *basesink)
+{
+ GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
+
+ GST_INFO_OBJECT(self, "stop");
+
+ if (self->watch_id != 0) {
+ g_source_remove(self->watch_id);
+ self->watch_id = 0;
+ }
+
+ if (self->server) {
+ bt_audio_service_close(g_io_channel_unix_get_fd(self->server));
+ g_io_channel_unref(self->server);
+ self->server = NULL;
+ }
+
+ if (self->stream) {
+ g_io_channel_flush(self->stream, NULL);
+ g_io_channel_close(self->stream);
+ g_io_channel_unref(self->stream);
+ self->stream = NULL;
+ }
+
+ if (self->data) {
+ g_free(self->data);
+ self->data = NULL;
+ }
+
+ if (self->stream_caps) {
+ gst_caps_unref(self->stream_caps);
+ self->stream_caps = NULL;
+ }
+
+ if (self->dev_caps) {
+ gst_caps_unref(self->dev_caps);
+ self->dev_caps = NULL;
+ }
+
+ return TRUE;
+}
+
+static void gst_avdtp_sink_finalize(GObject *object)
+{
+ GstAvdtpSink *self = GST_AVDTP_SINK(object);
+
+ if (self->data)
+ gst_avdtp_sink_stop(GST_BASE_SINK(self));
+
+ if (self->device)
+ g_free(self->device);
+
+ g_mutex_free(self->sink_lock);
+
+ G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+static void gst_avdtp_sink_set_property(GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GstAvdtpSink *sink = GST_AVDTP_SINK(object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ if (sink->device)
+ g_free(sink->device);
+ sink->device = g_value_dup_string(value);
+ break;
+
+ case PROP_AUTOCONNECT:
+ sink->autoconnect = g_value_get_boolean(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gst_avdtp_sink_get_property(GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GstAvdtpSink *sink = GST_AVDTP_SINK(object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ g_value_set_string(value, sink->device);
+ break;
+
+ case PROP_AUTOCONNECT:
+ g_value_set_boolean(value, sink->autoconnect);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static gint gst_avdtp_sink_bluetooth_recvmsg_fd(GstAvdtpSink *sink)
+{
+ int err, ret;
+
+ ret = bt_audio_service_get_data_fd(
+ g_io_channel_unix_get_fd(sink->server));
+
+ if (ret < 0) {
+ err = errno;
+ GST_ERROR_OBJECT(sink, "Unable to receive fd: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ sink->stream = g_io_channel_unix_new(ret);
+ GST_DEBUG_OBJECT(sink, "stream_fd=%d", ret);
+
+ return 0;
+}
+
+static gboolean gst_avdtp_sink_init_sbc_pkt_conf(GstAvdtpSink *sink,
+ GstCaps *caps,
+ sbc_capabilities_t *pkt)
+{
+ sbc_capabilities_t *cfg = &sink->data->caps.sbc_capabilities;
+ const GValue *value = NULL;
+ const char *pref, *name;
+ gint rate, subbands, blocks;
+ GstStructure *structure = gst_caps_get_structure(caps, 0);
+
+ name = gst_structure_get_name(structure);
+
+ if (!(IS_SBC(name))) {
+ GST_ERROR_OBJECT(sink, "Unexpected format %s, "
+ "was expecting sbc", name);
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "rate");
+ rate = g_value_get_int(value);
+ if (rate == 44100)
+ cfg->frequency = BT_SBC_SAMPLING_FREQ_44100;
+ else if (rate == 48000)
+ cfg->frequency = BT_SBC_SAMPLING_FREQ_48000;
+ else if (rate == 32000)
+ cfg->frequency = BT_SBC_SAMPLING_FREQ_32000;
+ else if (rate == 16000)
+ cfg->frequency = BT_SBC_SAMPLING_FREQ_16000;
+ else {
+ GST_ERROR_OBJECT(sink, "Invalid rate while setting caps");
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "mode");
+ pref = g_value_get_string(value);
+ if (strcmp(pref, "mono") == 0)
+ cfg->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
+ else if (strcmp(pref, "dual") == 0)
+ cfg->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
+ else if (strcmp(pref, "stereo") == 0)
+ cfg->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
+ else if (strcmp(pref, "joint") == 0)
+ cfg->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+ else {
+ GST_ERROR_OBJECT(sink, "Invalid mode %s", pref);
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "allocation");
+ pref = g_value_get_string(value);
+ if (strcmp(pref, "loudness") == 0)
+ cfg->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
+ else if (strcmp(pref, "snr") == 0)
+ cfg->allocation_method = BT_A2DP_ALLOCATION_SNR;
+ else {
+ GST_ERROR_OBJECT(sink, "Invalid allocation: %s", pref);
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "subbands");
+ subbands = g_value_get_int(value);
+ if (subbands == 8)
+ cfg->subbands = BT_A2DP_SUBBANDS_8;
+ else if (subbands == 4)
+ cfg->subbands = BT_A2DP_SUBBANDS_4;
+ else {
+ GST_ERROR_OBJECT(sink, "Invalid subbands %d", subbands);
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "blocks");
+ blocks = g_value_get_int(value);
+ if (blocks == 16)
+ cfg->block_length = BT_A2DP_BLOCK_LENGTH_16;
+ else if (blocks == 12)
+ cfg->block_length = BT_A2DP_BLOCK_LENGTH_12;
+ else if (blocks == 8)
+ cfg->block_length = BT_A2DP_BLOCK_LENGTH_8;
+ else if (blocks == 4)
+ cfg->block_length = BT_A2DP_BLOCK_LENGTH_4;
+ else {
+ GST_ERROR_OBJECT(sink, "Invalid blocks %d", blocks);
+ return FALSE;
+ }
+
+ value = gst_structure_get_value(structure, "bitpool");
+ cfg->max_bitpool = cfg->min_bitpool = g_value_get_int(value);
+
+ memcpy(pkt, cfg, sizeof(*pkt));
+
+ return TRUE;
+}
+
+static gboolean gst_avdtp_sink_conf_recv_stream_fd(
+ GstAvdtpSink *self)
+{
+ struct bluetooth_data *data = self->data;
+ gint ret;
+ GIOError err;
+ GError *gerr = NULL;
+ GIOStatus status;
+ GIOFlags flags;
+ gsize read;
+
+ ret = gst_avdtp_sink_bluetooth_recvmsg_fd(self);
+ if (ret < 0)
+ return FALSE;
+
+ if (!self->stream) {
+ GST_ERROR_OBJECT(self, "Error while configuring device: "
+ "could not acquire audio socket");
+ return FALSE;
+ }
+
+ /* set stream socket to nonblock */
+ GST_LOG_OBJECT(self, "setting stream socket to nonblock");
+ flags = g_io_channel_get_flags(self->stream);
+ flags |= G_IO_FLAG_NONBLOCK;
+ status = g_io_channel_set_flags(self->stream, flags, &gerr);
+ if (status != G_IO_STATUS_NORMAL) {
+ if (gerr)
+ GST_WARNING_OBJECT(self, "Error while "
+ "setting server socket to nonblock: "
+ "%s", gerr->message);
+ else
+ GST_WARNING_OBJECT(self, "Error while "
+ "setting server "
+ "socket to nonblock");
+ }
+
+ /* It is possible there is some outstanding
+ data in the pipe - we have to empty it */
+ GST_LOG_OBJECT(self, "emptying stream pipe");
+ while (1) {
+ err = g_io_channel_read(self->stream, data->buffer,
+ (gsize) data->link_mtu,
+ &read);
+ if (err != G_IO_ERROR_NONE || read <= 0)
+ break;
+ }
+
+ /* set stream socket to block */
+ GST_LOG_OBJECT(self, "setting stream socket to block");
+ flags = g_io_channel_get_flags(self->stream);
+ flags &= ~G_IO_FLAG_NONBLOCK;
+ status = g_io_channel_set_flags(self->stream, flags, &gerr);
+ if (status != G_IO_STATUS_NORMAL) {
+ if (gerr)
+ GST_WARNING_OBJECT(self, "Error while "
+ "setting server socket to block:"
+ "%s", gerr->message);
+ else
+ GST_WARNING_OBJECT(self, "Error while "
+ "setting server "
+ "socket to block");
+ }
+
+ memset(data->buffer, 0, sizeof(data->buffer));
+
+ return TRUE;
+}
+
+static gboolean server_callback(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ GstAvdtpSink *sink;
+
+ if (cond & G_IO_HUP || cond & G_IO_NVAL)
+ return FALSE;
+ else if (cond & G_IO_ERR) {
+ sink = GST_AVDTP_SINK(data);
+ GST_WARNING_OBJECT(sink, "Untreated callback G_IO_ERR");
+ }
+
+ return TRUE;
+}
+
+static GstStructure *gst_avdtp_sink_parse_sbc_caps(
+ GstAvdtpSink *self, sbc_capabilities_t *sbc)
+{
+ GstStructure *structure;
+ GValue *value;
+ GValue *list;
+ gboolean mono, stereo;
+
+ structure = gst_structure_empty_new("audio/x-sbc");
+ value = g_value_init(g_new0(GValue, 1), G_TYPE_STRING);
+
+ /* mode */
+ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
+ if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
+ g_value_set_static_string(value, "mono");
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) {
+ g_value_set_static_string(value, "stereo");
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) {
+ g_value_set_static_string(value, "dual");
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) {
+ g_value_set_static_string(value, "joint");
+ gst_value_list_prepend_value(list, value);
+ }
+ g_value_unset(value);
+ if (list) {
+ gst_structure_set_value(structure, "mode", list);
+ g_free(list);
+ list = NULL;
+ }
+
+ /* subbands */
+ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
+ value = g_value_init(value, G_TYPE_INT);
+ if (sbc->subbands & BT_A2DP_SUBBANDS_4) {
+ g_value_set_int(value, 4);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->subbands & BT_A2DP_SUBBANDS_8) {
+ g_value_set_int(value, 8);
+ gst_value_list_prepend_value(list, value);
+ }
+ g_value_unset(value);
+ if (list) {
+ gst_structure_set_value(structure, "subbands", list);
+ g_free(list);
+ list = NULL;
+ }
+
+ /* blocks */
+ value = g_value_init(value, G_TYPE_INT);
+ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
+ if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) {
+ g_value_set_int(value, 16);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) {
+ g_value_set_int(value, 12);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) {
+ g_value_set_int(value, 8);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) {
+ g_value_set_int(value, 4);
+ gst_value_list_prepend_value(list, value);
+ }
+ g_value_unset(value);
+ if (list) {
+ gst_structure_set_value(structure, "blocks", list);
+ g_free(list);
+ list = NULL;
+ }
+
+ /* allocation */
+ g_value_init(value, G_TYPE_STRING);
+ list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST);
+ if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) {
+ g_value_set_static_string(value, "loudness");
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) {
+ g_value_set_static_string(value, "snr");
+ gst_value_list_prepend_value(list, value);
+ }
+ g_value_unset(value);
+ if (list) {
+ gst_structure_set_value(structure, "allocation", list);
+ g_free(list);
+ list = NULL;
+ }
+
+ /* rate */
+ g_value_init(value, G_TYPE_INT);
+ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
+ if (sbc->frequency & BT_SBC_SAMPLING_FREQ_48000) {
+ g_value_set_int(value, 48000);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->frequency & BT_SBC_SAMPLING_FREQ_44100) {
+ g_value_set_int(value, 44100);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->frequency & BT_SBC_SAMPLING_FREQ_32000) {
+ g_value_set_int(value, 32000);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (sbc->frequency & BT_SBC_SAMPLING_FREQ_16000) {
+ g_value_set_int(value, 16000);
+ gst_value_list_prepend_value(list, value);
+ }
+ g_value_unset(value);
+ if (list) {
+ gst_structure_set_value(structure, "rate", list);
+ g_free(list);
+ list = NULL;
+ }
+
+ /* bitpool */
+ value = g_value_init(value, GST_TYPE_INT_RANGE);
+ gst_value_set_int_range(value,
+ MIN(sbc->min_bitpool, TEMPLATE_MAX_BITPOOL),
+ MIN(sbc->max_bitpool, TEMPLATE_MAX_BITPOOL));
+ gst_structure_set_value(structure, "bitpool", value);
+ g_value_unset(value);
+
+ /* channels */
+ mono = FALSE;
+ stereo = FALSE;
+ if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
+ mono = TRUE;
+ if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
+ (sbc->channel_mode &
+ BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
+ (sbc->channel_mode &
+ BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
+ stereo = TRUE;
+
+ if (mono && stereo) {
+ g_value_init(value, GST_TYPE_INT_RANGE);
+ gst_value_set_int_range(value, 1, 2);
+ } else {
+ g_value_init(value, G_TYPE_INT);
+ if (mono)
+ g_value_set_int(value, 1);
+ else if (stereo)
+ g_value_set_int(value, 2);
+ else {
+ GST_ERROR_OBJECT(self,
+ "Unexpected number of channels");
+ g_value_set_int(value, 0);
+ }
+ }
+
+ gst_structure_set_value(structure, "channels", value);
+ g_free(value);
+
+ return structure;
+}
+
+static GstStructure *gst_avdtp_sink_parse_mpeg_caps(
+ GstAvdtpSink *self, mpeg_capabilities_t *mpeg)
+{
+ GstStructure *structure;
+ GValue *value;
+ GValue *list;
+ gboolean valid_layer = FALSE;
+ gboolean mono, stereo;
+
+ GST_LOG_OBJECT(self, "parsing mpeg caps");
+
+ structure = gst_structure_empty_new("audio/mpeg");
+ value = g_new0(GValue, 1);
+ g_value_init(value, G_TYPE_INT);
+
+ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
+ g_value_set_int(value, 1);
+ gst_value_list_prepend_value(list, value);
+ g_value_set_int(value, 2);
+ gst_value_list_prepend_value(list, value);
+ gst_structure_set_value(structure, "mpegversion", list);
+ g_free(list);
+
+ /* layer */
+ GST_LOG_OBJECT(self, "setting mpeg layer");
+ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
+ if (mpeg->layer & BT_MPEG_LAYER_1) {
+ g_value_set_int(value, 1);
+ gst_value_list_prepend_value(list, value);
+ valid_layer = TRUE;
+ }
+ if (mpeg->layer & BT_MPEG_LAYER_2) {
+ g_value_set_int(value, 2);
+ gst_value_list_prepend_value(list, value);
+ valid_layer = TRUE;
+ }
+ if (mpeg->layer & BT_MPEG_LAYER_3) {
+ g_value_set_int(value, 3);
+ gst_value_list_prepend_value(list, value);
+ valid_layer = TRUE;
+ }
+ if (list) {
+ gst_structure_set_value(structure, "layer", list);
+ g_free(list);
+ list = NULL;
+ }
+
+ if (!valid_layer) {
+ gst_structure_free(structure);
+ g_free(value);
+ return NULL;
+ }
+
+ /* rate */
+ GST_LOG_OBJECT(self, "setting mpeg rate");
+ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
+ if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_48000) {
+ g_value_set_int(value, 48000);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_44100) {
+ g_value_set_int(value, 44100);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_32000) {
+ g_value_set_int(value, 32000);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_24000) {
+ g_value_set_int(value, 24000);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_22050) {
+ g_value_set_int(value, 22050);
+ gst_value_list_prepend_value(list, value);
+ }
+ if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_16000) {
+ g_value_set_int(value, 16000);
+ gst_value_list_prepend_value(list, value);
+ }
+ g_value_unset(value);
+ if (list) {
+ gst_structure_set_value(structure, "rate", list);
+ g_free(list);
+ list = NULL;
+ }
+
+ /* channels */
+ GST_LOG_OBJECT(self, "setting mpeg channels");
+ mono = FALSE;
+ stereo = FALSE;
+ if (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
+ mono = TRUE;
+ if ((mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
+ (mpeg->channel_mode &
+ BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
+ (mpeg->channel_mode &
+ BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
+ stereo = TRUE;
+
+ if (mono && stereo) {
+ g_value_init(value, GST_TYPE_INT_RANGE);
+ gst_value_set_int_range(value, 1, 2);
+ } else {
+ g_value_init(value, G_TYPE_INT);
+ if (mono)
+ g_value_set_int(value, 1);
+ else if (stereo)
+ g_value_set_int(value, 2);
+ else {
+ GST_ERROR_OBJECT(self,
+ "Unexpected number of channels");
+ g_value_set_int(value, 0);
+ }
+ }
+ gst_structure_set_value(structure, "channels", value);
+ g_free(value);
+
+ return structure;
+}
+
+static gboolean gst_avdtp_sink_update_caps(GstAvdtpSink *self)
+{
+ sbc_capabilities_t *sbc = &self->data->caps.sbc_capabilities;
+ mpeg_capabilities_t *mpeg = &self->data->caps.mpeg_capabilities;
+ GstStructure *sbc_structure;
+ GstStructure *mpeg_structure;
+ gchar *tmp;
+
+ GST_LOG_OBJECT(self, "updating device caps");
+
+ sbc_structure = gst_avdtp_sink_parse_sbc_caps(self, sbc);
+ mpeg_structure = gst_avdtp_sink_parse_mpeg_caps(self, mpeg);
+
+ if (self->dev_caps != NULL)
+ gst_caps_unref(self->dev_caps);
+ self->dev_caps = gst_caps_new_full(sbc_structure, NULL);
+ if (mpeg_structure != NULL)
+ gst_caps_append_structure(self->dev_caps, mpeg_structure);
+
+ tmp = gst_caps_to_string(self->dev_caps);
+ GST_DEBUG_OBJECT(self, "Device capabilities: %s", tmp);
+ g_free(tmp);
+
+ return TRUE;
+}
+
+static gboolean gst_avdtp_sink_get_capabilities(GstAvdtpSink *self)
+{
+ gchar *buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_getcapabilities_req *req = (void *) buf;
+ struct bt_getcapabilities_rsp *rsp = (void *) buf;
+ GIOError io_error;
+
+ memset(req, 0, BT_AUDIO_IPC_PACKET_SIZE);
+
+ req->h.msg_type = BT_GETCAPABILITIES_REQ;
+ if (self->device == NULL)
+ return FALSE;
+ strncpy(req->device, self->device, 18);
+ if (self->autoconnect)
+ req->flags |= BT_FLAG_AUTOCONNECT;
+
+ io_error = gst_avdtp_sink_audioservice_send(self, &req->h);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error while asking device caps");
+ return FALSE;
+ }
+
+ io_error = gst_avdtp_sink_audioservice_expect(self,
+ &rsp->rsp_h.msg_h, BT_GETCAPABILITIES_RSP);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error while getting device caps");
+ return FALSE;
+ }
+
+ if (rsp->rsp_h.posix_errno != 0) {
+ GST_ERROR_OBJECT(self, "BT_GETCAPABILITIES failed : %s(%d)",
+ strerror(rsp->rsp_h.posix_errno),
+ rsp->rsp_h.posix_errno);
+ return FALSE;
+ }
+
+ memcpy(&self->data->caps, rsp, sizeof(*rsp));
+ if (!gst_avdtp_sink_update_caps(self)) {
+ GST_WARNING_OBJECT(self, "failed to update capabilities");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gint gst_avdtp_sink_get_channel_mode(const gchar *mode)
+{
+ if (strcmp(mode, "stereo") == 0)
+ return BT_A2DP_CHANNEL_MODE_STEREO;
+ else if (strcmp(mode, "joint") == 0)
+ return BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+ else if (strcmp(mode, "dual") == 0)
+ return BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
+ else if (strcmp(mode, "mono") == 0)
+ return BT_A2DP_CHANNEL_MODE_MONO;
+ else
+ return -1;
+}
+
+static void gst_avdtp_sink_tag(const GstTagList *taglist,
+ const gchar* tag, gpointer user_data)
+{
+ gboolean crc;
+ gchar *channel_mode = NULL;
+ GstAvdtpSink *self = GST_AVDTP_SINK(user_data);
+
+ if (strcmp(tag, "has-crc") == 0) {
+
+ if (!gst_tag_list_get_boolean(taglist, tag, &crc)) {
+ GST_WARNING_OBJECT(self, "failed to get crc tag");
+ return;
+ }
+
+ gst_avdtp_sink_set_crc(self, crc);
+
+ } else if (strcmp(tag, "channel-mode") == 0) {
+
+ if (!gst_tag_list_get_string(taglist, tag, &channel_mode)) {
+ GST_WARNING_OBJECT(self,
+ "failed to get channel-mode tag");
+ return;
+ }
+
+ self->channel_mode = gst_avdtp_sink_get_channel_mode(
+ channel_mode);
+ if (self->channel_mode == -1)
+ GST_WARNING_OBJECT(self, "Received invalid channel "
+ "mode: %s", channel_mode);
+ g_free(channel_mode);
+
+ } else
+ GST_DEBUG_OBJECT(self, "received unused tag: %s", tag);
+}
+
+static gboolean gst_avdtp_sink_event(GstBaseSink *basesink,
+ GstEvent *event)
+{
+ GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
+ GstTagList *taglist = NULL;
+
+ if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {
+ /* we check the tags, mp3 has tags that are importants and
+ * are outside caps */
+ gst_event_parse_tag(event, &taglist);
+ gst_tag_list_foreach(taglist, gst_avdtp_sink_tag, self);
+ }
+
+ return TRUE;
+}
+
+static gboolean gst_avdtp_sink_start(GstBaseSink *basesink)
+{
+ GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
+ gint sk;
+ gint err;
+
+ GST_INFO_OBJECT(self, "start");
+
+ self->watch_id = 0;
+
+ sk = bt_audio_service_open();
+ if (sk <= 0) {
+ err = errno;
+ GST_ERROR_OBJECT(self, "Cannot open connection to bt "
+ "audio service: %s %d", strerror(err), err);
+ goto failed;
+ }
+
+ self->server = g_io_channel_unix_new(sk);
+ self->watch_id = g_io_add_watch(self->server, G_IO_HUP | G_IO_ERR |
+ G_IO_NVAL, server_callback, self);
+
+ self->data = g_new0(struct bluetooth_data, 1);
+ memset(self->data, 0, sizeof(struct bluetooth_data));
+
+ self->stream = NULL;
+ self->stream_caps = NULL;
+ self->mp3_using_crc = -1;
+ self->channel_mode = -1;
+
+ if (!gst_avdtp_sink_get_capabilities(self)) {
+ GST_ERROR_OBJECT(self, "failed to get capabilities "
+ "from device");
+ goto failed;
+ }
+
+ return TRUE;
+
+failed:
+ bt_audio_service_close(sk);
+ return FALSE;
+}
+
+static gboolean gst_avdtp_sink_stream_start(GstAvdtpSink *self)
+{
+ gchar buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_streamstart_req *req = (void *) buf;
+ struct bt_streamstart_rsp *rsp = (void *) buf;
+ struct bt_streamfd_ind *ind = (void*) buf;
+ GIOError io_error;
+
+ GST_DEBUG_OBJECT(self, "stream start");
+
+ memset (req, 0, sizeof(buf));
+ req->h.msg_type = BT_STREAMSTART_REQ;
+
+ io_error = gst_avdtp_sink_audioservice_send(self, &req->h);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error ocurred while sending "
+ "start packet");
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT(self, "stream start packet sent");
+
+ io_error = gst_avdtp_sink_audioservice_expect(self,
+ &rsp->rsp_h.msg_h, BT_STREAMSTART_RSP);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error while stream "
+ "start confirmation");
+ return FALSE;
+ }
+
+ if (rsp->rsp_h.posix_errno != 0) {
+ GST_ERROR_OBJECT(self, "BT_STREAMSTART_RSP failed : %s(%d)",
+ strerror(rsp->rsp_h.posix_errno),
+ rsp->rsp_h.posix_errno);
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT(self, "stream started");
+
+ io_error = gst_avdtp_sink_audioservice_expect(self, &ind->h,
+ BT_STREAMFD_IND);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error while receiving "
+ "stream filedescriptor");
+ return FALSE;
+ }
+
+ if (!gst_avdtp_sink_conf_recv_stream_fd(self))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean gst_avdtp_sink_init_mp3_pkt_conf(
+ GstAvdtpSink *self, GstCaps *caps,
+ mpeg_capabilities_t *pkt)
+{
+ const GValue *value = NULL;
+ gint rate, layer;
+ const gchar* name;
+ GstStructure *structure = gst_caps_get_structure(caps, 0);
+
+ name = gst_structure_get_name(structure);
+
+ if (!(IS_MPEG_AUDIO(name))) {
+ GST_ERROR_OBJECT(self, "Unexpected format %s, "
+ "was expecting mp3", name);
+ return FALSE;
+ }
+
+ /* layer */
+ value = gst_structure_get_value(structure, "layer");
+ layer = g_value_get_int(value);
+ if (layer == 1)
+ pkt->layer = BT_MPEG_LAYER_1;
+ else if (layer == 2)
+ pkt->layer = BT_MPEG_LAYER_2;
+ else if (layer == 3)
+ pkt->layer = BT_MPEG_LAYER_3;
+ else {
+ GST_ERROR_OBJECT(self, "Unexpected layer: %d", layer);
+ return FALSE;
+ }
+
+ /* crc */
+ if (self->mp3_using_crc != -1)
+ pkt->crc = self->mp3_using_crc;
+ else {
+ GST_ERROR_OBJECT(self, "No info about crc was received, "
+ " can't proceed");
+ return FALSE;
+ }
+
+ /* channel mode */
+ if (self->channel_mode != -1)
+ pkt->channel_mode = self->channel_mode;
+ else {
+ GST_ERROR_OBJECT(self, "No info about channel mode "
+ "received, can't proceed");
+ return FALSE;
+ }
+
+ /* mpf - we will only use the mandatory one */
+ pkt->mpf = 0;
+
+ value = gst_structure_get_value(structure, "rate");
+ rate = g_value_get_int(value);
+ if (rate == 44100)
+ pkt->frequency = BT_MPEG_SAMPLING_FREQ_44100;
+ else if (rate == 48000)
+ pkt->frequency = BT_MPEG_SAMPLING_FREQ_48000;
+ else if (rate == 32000)
+ pkt->frequency = BT_MPEG_SAMPLING_FREQ_32000;
+ else if (rate == 24000)
+ pkt->frequency = BT_MPEG_SAMPLING_FREQ_24000;
+ else if (rate == 22050)
+ pkt->frequency = BT_MPEG_SAMPLING_FREQ_22050;
+ else if (rate == 16000)
+ pkt->frequency = BT_MPEG_SAMPLING_FREQ_16000;
+ else {
+ GST_ERROR_OBJECT(self, "Invalid rate while setting caps");
+ return FALSE;
+ }
+
+ /* vbr - we always say its vbr, we don't have how to know it */
+ pkt->bitrate = 0x8000;
+
+ return TRUE;
+}
+
+static gboolean gst_avdtp_sink_configure(GstAvdtpSink *self,
+ GstCaps *caps)
+{
+ gchar buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_setconfiguration_req *req = (void *) buf;
+ struct bt_setconfiguration_rsp *rsp = (void *) buf;
+ gboolean ret;
+ GIOError io_error;
+ gchar *temp;
+ GstStructure *structure;
+
+ temp = gst_caps_to_string(caps);
+ GST_DEBUG_OBJECT(self, "configuring device with caps: %s", temp);
+ g_free(temp);
+
+ memset (req, 0, sizeof(buf));
+ req->h.msg_type = BT_SETCONFIGURATION_REQ;
+ req->access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE;
+ strncpy(req->device, self->device, 18);
+ structure = gst_caps_get_structure(caps, 0);
+
+ if (gst_structure_has_name(structure, "audio/x-sbc"))
+ ret = gst_avdtp_sink_init_sbc_pkt_conf(self, caps,
+ &req->sbc_capabilities);
+ else if (gst_structure_has_name(structure, "audio/mpeg"))
+ ret = gst_avdtp_sink_init_mp3_pkt_conf(self, caps,
+ &req->mpeg_capabilities);
+ else
+ ret = FALSE;
+
+ if (!ret) {
+ GST_ERROR_OBJECT(self, "Couldn't parse caps "
+ "to packet configuration");
+ return FALSE;
+ }
+
+ io_error = gst_avdtp_sink_audioservice_send(self, &req->h);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error ocurred while sending "
+ "configurarion packet");
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT(self, "configuration packet sent");
+
+ io_error = gst_avdtp_sink_audioservice_expect(self,
+ &rsp->rsp_h.msg_h, BT_SETCONFIGURATION_RSP);
+ if (io_error != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error while receiving device "
+ "confirmation");
+ return FALSE;
+ }
+
+ if (rsp->rsp_h.posix_errno != 0) {
+ GST_ERROR_OBJECT(self, "BT_SETCONFIGURATION_RSP failed : "
+ "%s(%d)",
+ strerror(rsp->rsp_h.posix_errno),
+ rsp->rsp_h.posix_errno);
+ return FALSE;
+ }
+
+ self->data->link_mtu = rsp->link_mtu;
+ GST_DEBUG_OBJECT(self, "configuration set");
+
+ return TRUE;
+}
+
+static GstFlowReturn gst_avdtp_sink_preroll(GstBaseSink *basesink,
+ GstBuffer *buffer)
+{
+ GstAvdtpSink *sink = GST_AVDTP_SINK(basesink);
+ gboolean ret;
+
+ GST_AVDTP_SINK_MUTEX_LOCK(sink);
+
+ ret = gst_avdtp_sink_stream_start(sink);
+
+ GST_AVDTP_SINK_MUTEX_UNLOCK(sink);
+
+ if (!ret)
+ return GST_FLOW_ERROR;
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn gst_avdtp_sink_render(GstBaseSink *basesink,
+ GstBuffer *buffer)
+{
+ GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
+ gsize ret;
+ GIOError err;
+
+ err = g_io_channel_write(self->stream, (gchar*)GST_BUFFER_DATA(buffer),
+ (gsize)(GST_BUFFER_SIZE(buffer)), &ret);
+
+ if (err != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error while writting to socket: %d %s",
+ errno, strerror(errno));
+ return GST_FLOW_ERROR;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static gboolean gst_avdtp_sink_unlock(GstBaseSink *basesink)
+{
+ GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
+
+ if (self->stream != NULL)
+ g_io_channel_flush (self->stream, NULL);
+
+ return TRUE;
+}
+
+static GstFlowReturn gst_avdtp_sink_buffer_alloc(GstBaseSink *basesink,
+ guint64 offset, guint size, GstCaps* caps,
+ GstBuffer **buf)
+{
+ GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
+
+ *buf = gst_buffer_new_and_alloc(size);
+ if (!(*buf)) {
+ GST_ERROR_OBJECT(self, "buffer allocation failed");
+ return GST_FLOW_ERROR;
+ }
+
+ gst_buffer_set_caps(*buf, caps);
+
+ GST_BUFFER_OFFSET(*buf) = offset;
+
+ return GST_FLOW_OK;
+}
+
+static void gst_avdtp_sink_class_init(GstAvdtpSinkClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ object_class->finalize = GST_DEBUG_FUNCPTR(
+ gst_avdtp_sink_finalize);
+ object_class->set_property = GST_DEBUG_FUNCPTR(
+ gst_avdtp_sink_set_property);
+ object_class->get_property = GST_DEBUG_FUNCPTR(
+ gst_avdtp_sink_get_property);
+
+ basesink_class->start = GST_DEBUG_FUNCPTR(gst_avdtp_sink_start);
+ basesink_class->stop = GST_DEBUG_FUNCPTR(gst_avdtp_sink_stop);
+ basesink_class->render = GST_DEBUG_FUNCPTR(
+ gst_avdtp_sink_render);
+ basesink_class->preroll = GST_DEBUG_FUNCPTR(
+ gst_avdtp_sink_preroll);
+ basesink_class->unlock = GST_DEBUG_FUNCPTR(
+ gst_avdtp_sink_unlock);
+ basesink_class->event = GST_DEBUG_FUNCPTR(
+ gst_avdtp_sink_event);
+
+ basesink_class->buffer_alloc =
+ GST_DEBUG_FUNCPTR(gst_avdtp_sink_buffer_alloc);
+
+ g_object_class_install_property(object_class, PROP_DEVICE,
+ g_param_spec_string("device", "Device",
+ "Bluetooth remote device address",
+ NULL, G_PARAM_READWRITE));
+
+ g_object_class_install_property(object_class, PROP_AUTOCONNECT,
+ g_param_spec_boolean("auto-connect",
+ "Auto-connect",
+ "Automatically attempt to connect "
+ "to device", DEFAULT_AUTOCONNECT,
+ G_PARAM_READWRITE));
+
+ GST_DEBUG_CATEGORY_INIT(avdtp_sink_debug, "avdtpsink", 0,
+ "A2DP headset sink element");
+}
+
+static void gst_avdtp_sink_init(GstAvdtpSink *self,
+ GstAvdtpSinkClass *klass)
+{
+ self->device = NULL;
+ self->data = NULL;
+
+ self->stream = NULL;
+
+ self->dev_caps = NULL;
+
+ self->autoconnect = DEFAULT_AUTOCONNECT;
+
+ self->sink_lock = g_mutex_new();
+
+ /* FIXME this is for not synchronizing with clock, should be tested
+ * with devices to see the behaviour
+ gst_base_sink_set_sync(GST_BASE_SINK(self), FALSE);
+ */
+}
+
+static GIOError gst_avdtp_sink_audioservice_send(
+ GstAvdtpSink *self,
+ const bt_audio_msg_header_t *msg)
+{
+ GIOError error;
+ gsize written;
+
+ error = g_io_channel_write(self->server, (const gchar*) msg,
+ BT_AUDIO_IPC_PACKET_SIZE, &written);
+ if (error != G_IO_ERROR_NONE)
+ GST_ERROR_OBJECT(self, "Error sending data to audio service:"
+ " %s(%d)", strerror(errno), errno);
+
+ return error;
+}
+
+static GIOError gst_avdtp_sink_audioservice_recv(
+ GstAvdtpSink *self,
+ bt_audio_msg_header_t *inmsg)
+{
+ GIOError status;
+ gsize bytes_read;
+ const char *type;
+
+ status = g_io_channel_read(self->server, (gchar*) inmsg,
+ BT_AUDIO_IPC_PACKET_SIZE, &bytes_read);
+ if (status != G_IO_ERROR_NONE) {
+ GST_ERROR_OBJECT(self, "Error receiving data from "
+ "audio service");
+ return status;
+ }
+
+ type = bt_audio_strmsg(inmsg->msg_type);
+ if (!type) {
+ status = G_IO_ERROR_INVAL;
+ GST_ERROR_OBJECT(self, "Bogus message type %d "
+ "received from audio service",
+ inmsg->msg_type);
+ }
+
+ return status;
+}
+
+static GIOError gst_avdtp_sink_audioservice_expect(
+ GstAvdtpSink *self, bt_audio_msg_header_t *outmsg,
+ int expected_type)
+{
+ GIOError status;
+
+ status = gst_avdtp_sink_audioservice_recv(self, outmsg);
+ if (status != G_IO_ERROR_NONE)
+ return status;
+
+ if (outmsg->msg_type != expected_type)
+ status = G_IO_ERROR_INVAL;
+
+ return status;
+}
+
+gboolean gst_avdtp_sink_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "avdtpsink",
+ GST_RANK_NONE, GST_TYPE_AVDTP_SINK);
+}
+
+
+/* public functions */
+GstCaps *gst_avdtp_sink_get_device_caps(GstAvdtpSink *sink)
+{
+ if (sink->dev_caps == NULL)
+ return NULL;
+
+ return gst_caps_copy(sink->dev_caps);
+}
+
+gboolean gst_avdtp_sink_set_device_caps(GstAvdtpSink *self,
+ GstCaps *caps)
+{
+ gboolean ret;
+
+ GST_DEBUG_OBJECT(self, "setting device caps");
+ GST_AVDTP_SINK_MUTEX_LOCK(self);
+ ret = gst_avdtp_sink_configure(self, caps);
+
+ if (self->stream_caps)
+ gst_caps_unref(self->stream_caps);
+ self->stream_caps = gst_caps_ref(caps);
+
+ GST_AVDTP_SINK_MUTEX_UNLOCK(self);
+
+ return ret;
+}
+
+guint gst_avdtp_sink_get_link_mtu(GstAvdtpSink *sink)
+{
+ return sink->data->link_mtu;
+}
+
+void gst_avdtp_sink_set_device(GstAvdtpSink *self, const gchar* dev)
+{
+ if (self->device != NULL)
+ g_free(self->device);
+
+ GST_LOG_OBJECT(self, "Setting device: %s", dev);
+ self->device = g_strdup(dev);
+}
+
+gchar *gst_avdtp_sink_get_device(GstAvdtpSink *self)
+{
+ return g_strdup(self->device);
+}
+
+void gst_avdtp_sink_set_crc(GstAvdtpSink *self, gboolean crc)
+{
+ gint new_crc;
+
+ new_crc = crc ? CRC_PROTECTED : CRC_UNPROTECTED;
+
+ /* test if we already received a different crc */
+ if (self->mp3_using_crc != -1 && new_crc != self->mp3_using_crc) {
+ GST_WARNING_OBJECT(self, "crc changed during stream");
+ return;
+ }
+ self->mp3_using_crc = new_crc;
+
+}
+
+void gst_avdtp_sink_set_channel_mode(GstAvdtpSink *self,
+ const gchar *mode)
+{
+ gint new_mode;
+
+ new_mode = gst_avdtp_sink_get_channel_mode(mode);
+
+ if (self->channel_mode != -1 && new_mode != self->channel_mode) {
+ GST_WARNING_OBJECT(self, "channel mode changed during stream");
+ return;
+ }
+
+ self->channel_mode = new_mode;
+ if (self->channel_mode == -1)
+ GST_WARNING_OBJECT(self, "Received invalid channel "
+ "mode: %s", mode);
+}
+
+
diff --git a/utils/audio/gstavdtpsink.h b/utils/audio/gstavdtpsink.h
new file mode 100644
index 00000000..5ebc0fee
--- /dev/null
+++ b/utils/audio/gstavdtpsink.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GST_AVDTP_SINK_H
+#define __GST_AVDTP_SINK_H
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AVDTP_SINK \
+ (gst_avdtp_sink_get_type())
+#define GST_AVDTP_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVDTP_SINK,\
+ GstAvdtpSink))
+#define GST_AVDTP_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVDTP_SINK,\
+ GstAvdtpSinkClass))
+#define GST_IS_AVDTP_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVDTP_SINK))
+#define GST_IS_AVDTP_SINK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVDTP_SINK))
+
+typedef struct _GstAvdtpSink GstAvdtpSink;
+typedef struct _GstAvdtpSinkClass GstAvdtpSinkClass;
+
+struct bluetooth_data;
+
+struct _GstAvdtpSink {
+ GstBaseSink sink;
+
+ gchar *device;
+ GIOChannel *stream;
+
+ struct bluetooth_data *data;
+ gboolean autoconnect;
+ GIOChannel *server;
+
+ /* mp3 stream data (outside caps data)*/
+ gint mp3_using_crc;
+ gint channel_mode;
+
+ /* stream connection data */
+ GstCaps *stream_caps;
+
+ GstCaps *dev_caps;
+
+ GMutex *sink_lock;
+
+ guint watch_id;
+};
+
+struct _GstAvdtpSinkClass {
+ GstBaseSinkClass parent_class;
+};
+
+GType gst_avdtp_sink_get_type(void);
+
+GstCaps *gst_avdtp_sink_get_device_caps(GstAvdtpSink *sink);
+gboolean gst_avdtp_sink_set_device_caps(GstAvdtpSink *sink,
+ GstCaps *caps);
+
+guint gst_avdtp_sink_get_link_mtu(GstAvdtpSink *sink);
+
+void gst_avdtp_sink_set_device(GstAvdtpSink *sink,
+ const gchar* device);
+
+gchar *gst_avdtp_sink_get_device(GstAvdtpSink *sink);
+
+gboolean gst_avdtp_sink_plugin_init(GstPlugin *plugin);
+
+void gst_avdtp_sink_set_crc(GstAvdtpSink *self, gboolean crc);
+
+void gst_avdtp_sink_set_channel_mode(GstAvdtpSink *self,
+ const gchar *mode);
+
+
+G_END_DECLS
+
+#endif /* __GST_AVDTP_SINK_H */
diff --git a/utils/audio/gstbluetooth.c b/utils/audio/gstbluetooth.c
new file mode 100644
index 00000000..ffc69768
--- /dev/null
+++ b/utils/audio/gstbluetooth.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/gst.h>
+
+#include <string.h>
+
+#include "gstsbcutil.h"
+#include <sbc.h>
+
+#include "gstsbcenc.h"
+#include "gstsbcdec.h"
+#include "gstsbcparse.h"
+#include "gstavdtpsink.h"
+#include "gsta2dpsink.h"
+#include "gstrtpsbcpay.h"
+
+static GstStaticCaps sbc_caps = GST_STATIC_CAPS("audio/x-sbc");
+
+#define SBC_CAPS (gst_static_caps_get(&sbc_caps))
+
+static void sbc_typefind(GstTypeFind *tf, gpointer ignore)
+{
+ GstCaps *caps;
+ guint8 *aux;
+ sbc_t sbc;
+ guint8 *data = gst_type_find_peek(tf, 0, 32);
+
+ if (sbc_init(&sbc, 0) < 0)
+ return;
+
+ if (data == NULL || *data != 0x9c) /* SBC syncword */
+ 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);
+
+ gst_type_find_suggest(tf, GST_TYPE_FIND_POSSIBLE, caps);
+ gst_caps_unref(caps);
+}
+
+static gchar *sbc_exts[] = { "sbc", NULL };
+
+static gboolean plugin_init(GstPlugin *plugin)
+{
+ GST_INFO("Bluetooth plugin %s", VERSION);
+
+ if (gst_type_find_register(plugin, "sbc",
+ GST_RANK_PRIMARY, sbc_typefind, sbc_exts,
+ SBC_CAPS, NULL, NULL) == FALSE)
+ return FALSE;
+
+ if (!gst_sbc_enc_plugin_init(plugin))
+ return FALSE;
+
+ if (!gst_sbc_dec_plugin_init(plugin))
+ return FALSE;
+
+ if (!gst_sbc_parse_plugin_init(plugin))
+ return FALSE;
+
+ if (!gst_avdtp_sink_plugin_init(plugin))
+ return FALSE;
+
+ if (!gst_a2dp_sink_plugin_init(plugin))
+ return FALSE;
+
+ if (!gst_rtp_sbc_pay_plugin_init(plugin))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR,
+ "bluetooth", "Bluetooth plugin library",
+ plugin_init, VERSION, "LGPL", "BlueZ", "http://www.bluez.org/")
diff --git a/utils/audio/gstrtpsbcpay.c b/utils/audio/gstrtpsbcpay.c
new file mode 100644
index 00000000..3627ad0b
--- /dev/null
+++ b/utils/audio/gstrtpsbcpay.c
@@ -0,0 +1,351 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstrtpsbcpay.h"
+#include <math.h>
+#include <string.h>
+
+#define RTP_SBC_PAYLOAD_HEADER_SIZE 1
+#define DEFAULT_MIN_FRAMES 0
+#define RTP_SBC_HEADER_TOTAL (12 + RTP_SBC_PAYLOAD_HEADER_SIZE)
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_payload {
+ guint8 frame_count:4;
+ guint8 rfa0:1;
+ guint8 is_last_fragment:1;
+ guint8 is_first_fragment:1;
+ guint8 is_fragmented:1;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct rtp_payload {
+ guint8 is_fragmented:1;
+ guint8 is_first_fragment:1;
+ guint8 is_last_fragment:1;
+ guint8 rfa0:1;
+ guint8 frame_count:4;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+enum {
+ PROP_0,
+ PROP_MIN_FRAMES
+};
+
+GST_DEBUG_CATEGORY_STATIC(gst_rtp_sbc_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_sbc_pay_debug
+
+GST_BOILERPLATE(GstRtpSBCPay, gst_rtp_sbc_pay, GstBaseRTPPayload,
+ GST_TYPE_BASE_RTP_PAYLOAD);
+
+static const GstElementDetails gst_rtp_sbc_pay_details =
+ GST_ELEMENT_DETAILS("RTP packet payloader",
+ "Codec/Payloader/Network",
+ "Payload SBC audio as RTP packets",
+ "Thiago Sousa Santos "
+ "<thiagoss@lcc.ufcg.edu.br>");
+
+static GstStaticPadTemplate gst_rtp_sbc_pay_sink_factory =
+ GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-sbc, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
+ "blocks = (int) { 4, 8, 12, 16 }, "
+ "subbands = (int) { 4, 8 }, "
+ "allocation = (string) { \"snr\", \"loudness\" }, "
+ "bitpool = (int) [ 2, 64 ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_sbc_pay_src_factory =
+ GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS(
+ "application/x-rtp, "
+ "media = (string) \"audio\","
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 16000, 32000, 44100, 48000 },"
+ "encoding-name = (string) \"SBC\"")
+ );
+
+static void gst_rtp_sbc_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_sbc_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gint gst_rtp_sbc_pay_get_frame_len(gint subbands, gint channels,
+ gint blocks, gint bitpool, const gchar* channel_mode)
+{
+ gint len;
+ gint join;
+
+ len = 4 + (4 * subbands * channels)/8;
+
+ if (strcmp(channel_mode, "mono") == 0 ||
+ strcmp(channel_mode, "dual") == 0)
+ len += ((blocks * channels * bitpool)+7) / 8;
+ else {
+ join = strcmp(channel_mode, "joint") == 0 ? 1 : 0;
+ len += ((join * subbands + blocks * bitpool)+7)/8;
+ }
+
+ return len;
+}
+
+static gboolean gst_rtp_sbc_pay_set_caps(GstBaseRTPPayload *payload,
+ GstCaps *caps)
+{
+ GstRtpSBCPay *sbcpay;
+ gint rate, subbands, channels, blocks, bitpool;
+ gint frame_len;
+ const gchar* channel_mode;
+ GstStructure *structure;
+
+ sbcpay = GST_RTP_SBC_PAY(payload);
+
+ structure = gst_caps_get_structure(caps, 0);
+ if (!gst_structure_get_int(structure, "rate", &rate))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "channels", &channels))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "blocks", &blocks))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "bitpool", &bitpool))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "subbands", &subbands))
+ return FALSE;
+
+ channel_mode = gst_structure_get_string(structure, "mode");
+ if (!channel_mode)
+ return FALSE;
+
+ frame_len = gst_rtp_sbc_pay_get_frame_len(subbands, channels, blocks,
+ bitpool, channel_mode);
+
+ sbcpay->frame_length = frame_len;
+
+ gst_basertppayload_set_options (payload, "audio", TRUE, "SBC", rate);
+
+ GST_DEBUG_OBJECT(payload, "calculated frame length: %d ", frame_len);
+
+ return gst_basertppayload_set_outcaps (payload, NULL);
+}
+
+static GstFlowReturn gst_rtp_sbc_pay_flush_buffers(GstRtpSBCPay *sbcpay)
+{
+ guint available;
+ guint max_payload;
+ GstBuffer* outbuf;
+ guint8 *payload_data;
+ guint frame_count;
+ guint payload_length;
+ struct rtp_payload *payload;
+
+ if (sbcpay->frame_length == 0) {
+ GST_ERROR_OBJECT(sbcpay, "Frame length is 0");
+ return GST_FLOW_ERROR;
+ }
+
+ available = gst_adapter_available(sbcpay->adapter);
+
+ max_payload = gst_rtp_buffer_calc_payload_len(
+ GST_BASE_RTP_PAYLOAD_MTU(sbcpay) - RTP_SBC_PAYLOAD_HEADER_SIZE,
+ 0, 0);
+
+ max_payload = MIN(max_payload, available);
+ frame_count = max_payload / sbcpay->frame_length;
+ payload_length = frame_count * sbcpay->frame_length;
+ if (payload_length == 0) /* Nothing to send */
+ return GST_FLOW_OK;
+
+ outbuf = gst_rtp_buffer_new_allocate(payload_length +
+ RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
+
+ gst_rtp_buffer_set_payload_type(outbuf,
+ GST_BASE_RTP_PAYLOAD_PT(sbcpay));
+
+ payload_data = gst_rtp_buffer_get_payload(outbuf);
+ payload = (struct rtp_payload*) payload_data;
+ memset(payload, 0, sizeof(struct rtp_payload));
+ payload->frame_count = frame_count;
+
+ gst_adapter_copy(sbcpay->adapter, payload_data +
+ RTP_SBC_PAYLOAD_HEADER_SIZE, 0, payload_length);
+ gst_adapter_flush(sbcpay->adapter, payload_length);
+
+ GST_BUFFER_TIMESTAMP(outbuf) = sbcpay->timestamp;
+ GST_DEBUG_OBJECT (sbcpay, "Pushing %d bytes", payload_length);
+
+ return gst_basertppayload_push(GST_BASE_RTP_PAYLOAD(sbcpay), outbuf);
+}
+
+static GstFlowReturn gst_rtp_sbc_pay_handle_buffer(GstBaseRTPPayload *payload,
+ GstBuffer *buffer)
+{
+ GstRtpSBCPay *sbcpay;
+ guint available;
+
+ /* FIXME check for negotiation */
+
+ sbcpay = GST_RTP_SBC_PAY(payload);
+ sbcpay->timestamp = GST_BUFFER_TIMESTAMP(buffer);
+
+ gst_adapter_push(sbcpay->adapter, buffer);
+
+ available = gst_adapter_available(sbcpay->adapter);
+ if (available + RTP_SBC_HEADER_TOTAL >=
+ GST_BASE_RTP_PAYLOAD_MTU(sbcpay) ||
+ (sbcpay->min_frames != -1 && available >
+ (sbcpay->min_frames * sbcpay->frame_length)))
+ return gst_rtp_sbc_pay_flush_buffers(sbcpay);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean gst_rtp_sbc_pay_handle_event(GstPad *pad,
+ GstEvent *event)
+{
+ GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY(GST_PAD_PARENT(pad));
+
+ switch (GST_EVENT_TYPE(event)) {
+ case GST_EVENT_EOS:
+ gst_rtp_sbc_pay_flush_buffers(sbcpay);
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void gst_rtp_sbc_pay_base_init(gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&gst_rtp_sbc_pay_sink_factory));
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&gst_rtp_sbc_pay_src_factory));
+
+ gst_element_class_set_details(element_class, &gst_rtp_sbc_pay_details);
+}
+
+static void gst_rtp_sbc_pay_finalize(GObject *object)
+{
+ GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY(object);
+ g_object_unref (sbcpay->adapter);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void gst_rtp_sbc_pay_class_init(GstRtpSBCPayClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseRTPPayloadClass *payload_class =
+ GST_BASE_RTP_PAYLOAD_CLASS(klass);
+
+ gobject_class = G_OBJECT_CLASS(klass);
+ parent_class = g_type_class_peek_parent(klass);
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_rtp_sbc_pay_finalize);
+ gobject_class->set_property = GST_DEBUG_FUNCPTR(
+ gst_rtp_sbc_pay_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR(
+ gst_rtp_sbc_pay_get_property);
+
+ payload_class->set_caps = GST_DEBUG_FUNCPTR(gst_rtp_sbc_pay_set_caps);
+ payload_class->handle_buffer = GST_DEBUG_FUNCPTR(
+ gst_rtp_sbc_pay_handle_buffer);
+ payload_class->handle_event = GST_DEBUG_FUNCPTR(
+ gst_rtp_sbc_pay_handle_event);
+
+ /* properties */
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_MIN_FRAMES,
+ g_param_spec_int ("min-frames", "minimum frame number",
+ "Minimum quantity of frames to send in one packet "
+ "(-1 for maximum allowed by the mtu)",
+ -1, G_MAXINT, DEFAULT_MIN_FRAMES, G_PARAM_READWRITE));
+
+ GST_DEBUG_CATEGORY_INIT(gst_rtp_sbc_pay_debug, "rtpsbcpay", 0,
+ "RTP SBC payloader");
+}
+
+static void gst_rtp_sbc_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpSBCPay *sbcpay;
+
+ sbcpay = GST_RTP_SBC_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MIN_FRAMES:
+ sbcpay->min_frames = g_value_get_int(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gst_rtp_sbc_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpSBCPay *sbcpay;
+
+ sbcpay = GST_RTP_SBC_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MIN_FRAMES:
+ g_value_set_int(value, sbcpay->min_frames);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gst_rtp_sbc_pay_init(GstRtpSBCPay *self, GstRtpSBCPayClass *klass)
+{
+ self->adapter = gst_adapter_new();
+ self->frame_length = 0;
+ self->timestamp = 0;
+
+ self->min_frames = DEFAULT_MIN_FRAMES;
+}
+
+gboolean gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpsbcpay",
+ GST_RANK_NONE, GST_TYPE_RTP_SBC_PAY);
+}
+
diff --git a/utils/audio/gstrtpsbcpay.h b/utils/audio/gstrtpsbcpay.h
new file mode 100644
index 00000000..e56fef35
--- /dev/null
+++ b/utils/audio/gstrtpsbcpay.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gst/gst.h>
+#include <gst/rtp/gstbasertppayload.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_SBC_PAY \
+ (gst_rtp_sbc_pay_get_type())
+#define GST_RTP_SBC_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SBC_PAY,\
+ GstRtpSBCPay))
+#define GST_RTP_SBC_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SBC_PAY,\
+ GstRtpSBCPayClass))
+#define GST_IS_RTP_SBC_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SBC_PAY))
+#define GST_IS_RTP_SBC_PAY_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SBC_PAY))
+
+typedef struct _GstRtpSBCPay GstRtpSBCPay;
+typedef struct _GstRtpSBCPayClass GstRtpSBCPayClass;
+
+struct _GstRtpSBCPay {
+ GstBaseRTPPayload base;
+
+ GstAdapter *adapter;
+ GstClockTime timestamp;
+
+ guint frame_length;
+
+ guint min_frames;
+};
+
+struct _GstRtpSBCPayClass {
+ GstBaseRTPPayloadClass parent_class;
+};
+
+GType gst_rtp_sbc_pay_get_type(void);
+
+gboolean gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
diff --git a/utils/audio/gstsbcdec.c b/utils/audio/gstsbcdec.c
new file mode 100644
index 00000000..43a40f44
--- /dev/null
+++ b/utils/audio/gstsbcdec.c
@@ -0,0 +1,223 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gstsbcdec.h"
+
+GST_DEBUG_CATEGORY_STATIC(sbc_dec_debug);
+#define GST_CAT_DEFAULT sbc_dec_debug
+
+GST_BOILERPLATE(GstSbcDec, gst_sbc_dec, GstElement, GST_TYPE_ELEMENT);
+
+static const GstElementDetails sbc_dec_details =
+ GST_ELEMENT_DETAILS("Bluetooth SBC decoder",
+ "Codec/Decoder/Audio",
+ "Decode a SBC audio stream",
+ "Marcel Holtmann <marcel@holtmann.org>");
+
+static GstStaticPadTemplate sbc_dec_sink_factory =
+ GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-sbc"));
+
+static GstStaticPadTemplate sbc_dec_src_factory =
+ GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-raw-int, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "endianness = (int) LITTLE_ENDIAN, "
+ "signed = (boolean) true, "
+ "width = (int) 16, "
+ "depth = (int) 16"));
+
+static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer)
+{
+ GstSbcDec *dec = GST_SBC_DEC(gst_pad_get_parent(pad));
+ GstFlowReturn res = GST_FLOW_OK;
+ guint size, codesize, offset = 0;
+ guint8 *data;
+ GstClockTime timestamp;
+
+ codesize = sbc_get_codesize(&dec->sbc);
+ timestamp = GST_BUFFER_TIMESTAMP(buffer);
+
+ if (dec->buffer) {
+ GstBuffer *temp = buffer;
+ buffer = gst_buffer_span(dec->buffer, 0, buffer,
+ GST_BUFFER_SIZE(dec->buffer) + GST_BUFFER_SIZE(buffer));
+ gst_buffer_unref(temp);
+ gst_buffer_unref(dec->buffer);
+ dec->buffer = NULL;
+ }
+
+ data = GST_BUFFER_DATA(buffer);
+ size = GST_BUFFER_SIZE(buffer);
+
+ while (offset < size) {
+ GstBuffer *output;
+ GstPadTemplate *template;
+ GstCaps *caps;
+ int consumed;
+
+ res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad,
+ GST_BUFFER_OFFSET_NONE,
+ codesize, NULL, &output);
+
+ if (res != GST_FLOW_OK)
+ goto done;
+
+ consumed = sbc_decode(&dec->sbc, data + offset, size - offset,
+ GST_BUFFER_DATA(output), codesize,
+ NULL);
+ if (consumed <= 0)
+ break;
+
+ /* we will reuse the same caps object */
+ if (dec->outcaps == NULL) {
+ caps = gst_caps_new_simple("audio/x-raw-int",
+ "rate", G_TYPE_INT,
+ gst_sbc_parse_rate_from_sbc(
+ dec->sbc.frequency),
+ "channels", G_TYPE_INT,
+ gst_sbc_get_channel_number(
+ dec->sbc.mode),
+ NULL);
+
+ template = gst_static_pad_template_get(&sbc_dec_src_factory);
+
+ dec->outcaps = gst_caps_intersect(caps,
+ gst_pad_template_get_caps(template));
+
+ gst_caps_unref(caps);
+ }
+
+ gst_buffer_set_caps(output, dec->outcaps);
+
+ /* FIXME get a real timestamp */
+ GST_BUFFER_TIMESTAMP(output) = GST_CLOCK_TIME_NONE;
+
+ res = gst_pad_push(dec->srcpad, output);
+ if (res != GST_FLOW_OK)
+ goto done;
+
+ offset += consumed;
+ }
+
+ if (offset < size)
+ dec->buffer = gst_buffer_create_sub(buffer,
+ offset, size - offset);
+
+done:
+ gst_buffer_unref(buffer);
+ gst_object_unref(dec);
+
+ return res;
+}
+
+static GstStateChangeReturn sbc_dec_change_state(GstElement *element,
+ GstStateChange transition)
+{
+ GstSbcDec *dec = GST_SBC_DEC(element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ GST_DEBUG("Setup subband codec");
+ if (dec->buffer) {
+ gst_buffer_unref(dec->buffer);
+ dec->buffer = NULL;
+ }
+ sbc_init(&dec->sbc, 0);
+ dec->outcaps = NULL;
+ break;
+
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_DEBUG("Finish subband codec");
+ if (dec->buffer) {
+ gst_buffer_unref(dec->buffer);
+ dec->buffer = NULL;
+ }
+ sbc_finish(&dec->sbc);
+ if (dec->outcaps) {
+ gst_caps_unref(dec->outcaps);
+ dec->outcaps = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return parent_class->change_state(element, transition);
+}
+
+static void gst_sbc_dec_base_init(gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&sbc_dec_sink_factory));
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&sbc_dec_src_factory));
+
+ gst_element_class_set_details(element_class, &sbc_dec_details);
+}
+
+static void gst_sbc_dec_class_init(GstSbcDecClass *klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ element_class->change_state = GST_DEBUG_FUNCPTR(sbc_dec_change_state);
+
+ GST_DEBUG_CATEGORY_INIT(sbc_dec_debug, "sbcdec", 0,
+ "SBC decoding element");
+}
+
+static void gst_sbc_dec_init(GstSbcDec *self, GstSbcDecClass *klass)
+{
+ self->sinkpad = gst_pad_new_from_static_template(
+ &sbc_dec_sink_factory, "sink");
+ gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(
+ sbc_dec_chain));
+ gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);
+
+ self->srcpad = gst_pad_new_from_static_template(
+ &sbc_dec_src_factory, "src");
+ gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
+
+ self->outcaps = NULL;
+}
+
+gboolean gst_sbc_dec_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "sbcdec",
+ GST_RANK_PRIMARY, GST_TYPE_SBC_DEC);
+}
+
+
diff --git a/utils/audio/gstsbcdec.h b/utils/audio/gstsbcdec.h
new file mode 100644
index 00000000..df687933
--- /dev/null
+++ b/utils/audio/gstsbcdec.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gst/gst.h>
+
+#include "sbc.h"
+#include "gstsbcutil.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SBC_DEC \
+ (gst_sbc_dec_get_type())
+#define GST_SBC_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_DEC,GstSbcDec))
+#define GST_SBC_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_DEC,GstSbcDecClass))
+#define GST_IS_SBC_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_DEC))
+#define GST_IS_SBC_DEC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_DEC))
+
+typedef struct _GstSbcDec GstSbcDec;
+typedef struct _GstSbcDecClass GstSbcDecClass;
+
+struct _GstSbcDec {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ GstBuffer *buffer;
+
+ /* caps for outgoing buffers */
+ GstCaps *outcaps;
+
+ sbc_t sbc;
+};
+
+struct _GstSbcDecClass {
+ GstElementClass parent_class;
+};
+
+GType gst_sbc_dec_get_type(void);
+
+gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin);
+
+G_END_DECLS
diff --git a/utils/audio/gstsbcenc.c b/utils/audio/gstsbcenc.c
new file mode 100644
index 00000000..65e3da5b
--- /dev/null
+++ b/utils/audio/gstsbcenc.c
@@ -0,0 +1,602 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gstsbcenc.h"
+#include "gstsbcutil.h"
+
+#define SBC_ENC_DEFAULT_MODE SBC_MODE_AUTO
+#define SBC_ENC_DEFAULT_BLOCKS 0
+#define SBC_ENC_DEFAULT_SUB_BANDS 0
+#define SBC_ENC_DEFAULT_ALLOCATION SBC_AM_AUTO
+#define SBC_ENC_DEFAULT_RATE 0
+#define SBC_ENC_DEFAULT_CHANNELS 0
+
+#define SBC_ENC_BITPOOL_AUTO 1
+#define SBC_ENC_BITPOOL_MIN 2
+#define SBC_ENC_BITPOOL_MIN_STR "2"
+#define SBC_ENC_BITPOOL_MAX 64
+#define SBC_ENC_BITPOOL_MAX_STR "64"
+
+GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug);
+#define GST_CAT_DEFAULT sbc_enc_debug
+
+#define GST_TYPE_SBC_MODE (gst_sbc_mode_get_type())
+
+static GType gst_sbc_mode_get_type(void)
+{
+ static GType sbc_mode_type = 0;
+ static GEnumValue sbc_modes[] = {
+ { SBC_MODE_MONO, "Mono", "mono" },
+ { SBC_MODE_DUAL_CHANNEL, "Dual Channel", "dual" },
+ { SBC_MODE_STEREO, "Stereo", "stereo"},
+ { SBC_MODE_JOINT_STEREO, "Joint Stereo", "joint" },
+ { SBC_MODE_AUTO, "Auto", "auto" },
+ { -1, NULL, NULL}
+ };
+
+ if (!sbc_mode_type)
+ sbc_mode_type = g_enum_register_static("GstSbcMode", sbc_modes);
+
+ return sbc_mode_type;
+}
+
+#define GST_TYPE_SBC_ALLOCATION (gst_sbc_allocation_get_type())
+
+static GType gst_sbc_allocation_get_type(void)
+{
+ static GType sbc_allocation_type = 0;
+ static GEnumValue sbc_allocations[] = {
+ { SBC_AM_LOUDNESS, "Loudness", "loudness" },
+ { SBC_AM_SNR, "SNR", "snr" },
+ { SBC_AM_AUTO, "Auto", "auto" },
+ { -1, NULL, NULL}
+ };
+
+ if (!sbc_allocation_type)
+ sbc_allocation_type = g_enum_register_static(
+ "GstSbcAllocation", sbc_allocations);
+
+ return sbc_allocation_type;
+}
+
+#define GST_TYPE_SBC_BLOCKS (gst_sbc_blocks_get_type())
+
+static GType gst_sbc_blocks_get_type(void)
+{
+ static GType sbc_blocks_type = 0;
+ static GEnumValue sbc_blocks[] = {
+ { 0, "Auto", "auto" },
+ { 4, "4", "4" },
+ { 8, "8", "8" },
+ { 12, "12", "12" },
+ { 16, "16", "16" },
+ { -1, NULL, NULL}
+ };
+
+ if (!sbc_blocks_type)
+ sbc_blocks_type = g_enum_register_static(
+ "GstSbcBlocks", sbc_blocks);
+
+ return sbc_blocks_type;
+}
+
+#define GST_TYPE_SBC_SUBBANDS (gst_sbc_subbands_get_type())
+
+static GType gst_sbc_subbands_get_type(void)
+{
+ static GType sbc_subbands_type = 0;
+ static GEnumValue sbc_subbands[] = {
+ { 0, "Auto", "auto" },
+ { 4, "4 subbands", "4" },
+ { 8, "8 subbands", "8" },
+ { -1, NULL, NULL}
+ };
+
+ if (!sbc_subbands_type)
+ sbc_subbands_type = g_enum_register_static(
+ "GstSbcSubbands", sbc_subbands);
+
+ return sbc_subbands_type;
+}
+
+enum {
+ PROP_0,
+ PROP_MODE,
+ PROP_ALLOCATION,
+ PROP_BLOCKS,
+ PROP_SUBBANDS,
+ PROP_BITPOOL
+};
+
+GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT);
+
+static const GstElementDetails sbc_enc_details =
+ GST_ELEMENT_DETAILS("Bluetooth SBC encoder",
+ "Codec/Encoder/Audio",
+ "Encode a SBC audio stream",
+ "Marcel Holtmann <marcel@holtmann.org>");
+
+static GstStaticPadTemplate sbc_enc_sink_factory =
+ GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-raw-int, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "endianness = (int) LITTLE_ENDIAN, "
+ "signed = (boolean) true, "
+ "width = (int) 16, "
+ "depth = (int) 16"));
+
+static GstStaticPadTemplate sbc_enc_src_factory =
+ GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-sbc, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
+ "blocks = (int) { 4, 8, 12, 16 }, "
+ "subbands = (int) { 4, 8 }, "
+ "allocation = (string) { \"snr\", \"loudness\" }, "
+ "bitpool = (int) [ " SBC_ENC_BITPOOL_MIN_STR
+ ", " SBC_ENC_BITPOOL_MAX_STR " ]"));
+
+gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps);
+
+static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc)
+{
+ GstCaps* src_caps;
+ GstStructure *structure;
+ GEnumValue *enum_value;
+ GEnumClass *enum_class;
+ GValue *value;
+
+ src_caps = gst_caps_copy(gst_pad_get_pad_template_caps(enc->srcpad));
+ structure = gst_caps_get_structure(src_caps, 0);
+
+ value = g_new0(GValue, 1);
+
+ if (enc->rate != 0)
+ gst_sbc_util_set_structure_int_param(structure, "rate",
+ enc->rate, value);
+
+ if (enc->channels != 0)
+ gst_sbc_util_set_structure_int_param(structure, "channels",
+ enc->channels, value);
+
+ if (enc->subbands != 0)
+ gst_sbc_util_set_structure_int_param(structure, "subbands",
+ enc->subbands, value);
+
+ if (enc->blocks != 0)
+ gst_sbc_util_set_structure_int_param(structure, "blocks",
+ enc->blocks, value);
+
+ if (enc->bitpool != SBC_ENC_BITPOOL_AUTO)
+ gst_sbc_util_set_structure_int_param(structure, "bitpool",
+ enc->bitpool, value);
+
+ if (enc->mode != SBC_ENC_DEFAULT_MODE) {
+ enum_class = g_type_class_ref(GST_TYPE_SBC_MODE);
+ enum_value = g_enum_get_value(enum_class, enc->mode);
+ gst_sbc_util_set_structure_string_param(structure, "mode",
+ enum_value->value_nick, value);
+ g_type_class_unref(enum_class);
+ }
+
+ if (enc->allocation != SBC_AM_AUTO) {
+ enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION);
+ enum_value = g_enum_get_value(enum_class, enc->allocation);
+ gst_sbc_util_set_structure_string_param(structure, "allocation",
+ enum_value->value_nick, value);
+ g_type_class_unref(enum_class);
+ }
+
+ g_free(value);
+
+ return src_caps;
+}
+
+static GstCaps* sbc_enc_src_getcaps (GstPad * pad)
+{
+ GstSbcEnc *enc;
+
+ enc = GST_SBC_ENC(GST_PAD_PARENT(pad));
+
+ return sbc_enc_generate_srcpad_caps(enc);
+}
+
+static gboolean sbc_enc_src_setcaps (GstPad *pad, GstCaps *caps)
+{
+ GstSbcEnc *enc = GST_SBC_ENC(GST_PAD_PARENT(pad));
+
+ GST_LOG_OBJECT(enc, "setting srcpad caps");
+
+ return gst_sbc_enc_fill_sbc_params(enc, caps);
+}
+
+static GstCaps* sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps)
+{
+ gchar *error_message = NULL;
+ GstCaps* result;
+
+ result = gst_sbc_util_caps_fixate(caps, &error_message);
+
+ if (!result) {
+ GST_WARNING_OBJECT (enc, "Invalid input caps caused parsing "
+ "error: %s", error_message);
+ g_free(error_message);
+ return NULL;
+ }
+
+ return result;
+}
+
+static GstCaps* sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc)
+{
+ GstCaps *caps;
+ gboolean res = TRUE;
+ GstCaps *result_caps = NULL;
+
+ caps = gst_pad_get_allowed_caps(enc->srcpad);
+ if (caps == NULL)
+ caps = sbc_enc_src_getcaps(enc->srcpad);
+
+ if (caps == GST_CAPS_NONE || gst_caps_is_empty(caps)) {
+ res = FALSE;
+ goto done;
+ }
+
+ result_caps = sbc_enc_src_caps_fixate(enc, caps);
+
+done:
+ gst_caps_unref(caps);
+
+ if (!res)
+ return NULL;
+
+ return result_caps;
+}
+
+static gboolean sbc_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstSbcEnc *enc;
+ GstStructure *structure;
+ GstCaps *src_caps;
+ gint rate, channels;
+ gboolean res;
+
+ enc = GST_SBC_ENC(GST_PAD_PARENT (pad));
+ structure = gst_caps_get_structure(caps, 0);
+
+ if (!gst_structure_get_int(structure, "rate", &rate))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "channels", &channels))
+ return FALSE;
+
+ enc->rate = rate;
+ enc->channels = channels;
+
+ src_caps = sbc_enc_get_fixed_srcpad_caps(enc);
+ if (!src_caps)
+ return FALSE;
+ res = gst_pad_set_caps(enc->srcpad, src_caps);
+ gst_caps_unref(src_caps);
+
+ return res;
+}
+
+gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps)
+{
+ if (!gst_caps_is_fixed(caps)) {
+ GST_DEBUG_OBJECT(enc, "didn't receive fixed caps, "
+ "returning false");
+ return FALSE;
+ }
+
+ if (!gst_sbc_util_fill_sbc_params(&enc->sbc, caps))
+ return FALSE;
+
+ if (enc->rate != 0 && gst_sbc_parse_rate_from_sbc(enc->sbc.frequency)
+ != enc->rate)
+ goto fail;
+
+ if (enc->channels != 0 && gst_sbc_get_channel_number(enc->sbc.mode)
+ != enc->channels)
+ goto fail;
+
+ if (enc->blocks != 0 && gst_sbc_parse_blocks_from_sbc(enc->sbc.blocks)
+ != enc->blocks)
+ goto fail;
+
+ if (enc->subbands != 0 && gst_sbc_parse_subbands_from_sbc(
+ enc->sbc.subbands) != enc->subbands)
+ goto fail;
+
+ if (enc->mode != SBC_ENC_DEFAULT_MODE && enc->sbc.mode != enc->mode)
+ goto fail;
+
+ if (enc->allocation != SBC_AM_AUTO &&
+ enc->sbc.allocation != enc->allocation)
+ goto fail;
+
+ if (enc->bitpool != SBC_ENC_BITPOOL_AUTO &&
+ enc->sbc.bitpool != enc->bitpool)
+ goto fail;
+
+ enc->codesize = sbc_get_codesize(&enc->sbc);
+ enc->frame_length = sbc_get_frame_length(&enc->sbc);
+ enc->frame_duration = sbc_get_frame_duration(&enc->sbc);
+
+ GST_DEBUG_OBJECT(enc, "codesize: %d, frame_length: %d, frame_duration:"
+ " %d", enc->codesize, enc->frame_length,
+ enc->frame_duration);
+
+ return TRUE;
+
+fail:
+ memset(&enc->sbc, 0, sizeof(sbc_t));
+ return FALSE;
+}
+
+static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer)
+{
+ GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad));
+ GstAdapter *adapter = enc->adapter;
+ GstFlowReturn res = GST_FLOW_OK;
+
+ gst_adapter_push(adapter, buffer);
+
+ while (gst_adapter_available(adapter) >= enc->codesize &&
+ res == GST_FLOW_OK) {
+ GstBuffer *output;
+ GstCaps *caps;
+ const guint8 *data;
+ gint consumed;
+
+ caps = GST_PAD_CAPS(enc->srcpad);
+ res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad,
+ GST_BUFFER_OFFSET_NONE,
+ enc->frame_length, caps,
+ &output);
+ if (res != GST_FLOW_OK)
+ goto done;
+
+ data = gst_adapter_peek(adapter, enc->codesize);
+
+ consumed = sbc_encode(&enc->sbc, (gpointer) data,
+ enc->codesize,
+ GST_BUFFER_DATA(output),
+ GST_BUFFER_SIZE(output), NULL);
+ if (consumed <= 0) {
+ GST_DEBUG_OBJECT (enc, "comsumed < 0, codesize: %d",
+ enc->codesize);
+ break;
+ }
+ gst_adapter_flush(adapter, consumed);
+
+ GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer);
+ /* we have only 1 frame */
+ GST_BUFFER_DURATION(output) = enc->frame_duration;
+
+ res = gst_pad_push(enc->srcpad, output);
+
+ if (res != GST_FLOW_OK)
+ goto done;
+ }
+
+done:
+ gst_object_unref(enc);
+
+ return res;
+}
+
+static GstStateChangeReturn sbc_enc_change_state(GstElement *element,
+ GstStateChange transition)
+{
+ GstSbcEnc *enc = GST_SBC_ENC(element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ GST_DEBUG("Setup subband codec");
+ sbc_init(&enc->sbc, 0);
+ break;
+
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_DEBUG("Finish subband codec");
+ sbc_finish(&enc->sbc);
+ break;
+
+ default:
+ break;
+ }
+
+ return parent_class->change_state(element, transition);
+}
+
+static void gst_sbc_enc_dispose(GObject *object)
+{
+ GstSbcEnc *enc = GST_SBC_ENC(object);
+
+ if (enc->adapter != NULL)
+ g_object_unref (G_OBJECT (enc->adapter));
+
+ enc->adapter = NULL;
+}
+
+static void gst_sbc_enc_base_init(gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&sbc_enc_sink_factory));
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&sbc_enc_src_factory));
+
+ gst_element_class_set_details(element_class, &sbc_enc_details);
+}
+
+static void gst_sbc_enc_set_property(GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GstSbcEnc *enc = GST_SBC_ENC(object);
+
+ /* changes to those properties will only happen on the next caps
+ * negotiation */
+
+ switch (prop_id) {
+ case PROP_MODE:
+ enc->mode = g_value_get_enum(value);
+ break;
+ case PROP_ALLOCATION:
+ enc->allocation = g_value_get_enum(value);
+ break;
+ case PROP_BLOCKS:
+ enc->blocks = g_value_get_enum(value);
+ break;
+ case PROP_SUBBANDS:
+ enc->subbands = g_value_get_enum(value);
+ break;
+ case PROP_BITPOOL:
+ enc->bitpool = g_value_get_int(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gst_sbc_enc_get_property(GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GstSbcEnc *enc = GST_SBC_ENC(object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ g_value_set_enum(value, enc->mode);
+ break;
+ case PROP_ALLOCATION:
+ g_value_set_enum(value, enc->allocation);
+ break;
+ case PROP_BLOCKS:
+ g_value_set_enum(value, enc->blocks);
+ break;
+ case PROP_SUBBANDS:
+ g_value_set_enum(value, enc->subbands);
+ break;
+ case PROP_BITPOOL:
+ g_value_set_int(value, enc->bitpool);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gst_sbc_enc_class_init(GstSbcEncClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ object_class->set_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_set_property);
+ object_class->get_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_get_property);
+ object_class->dispose = GST_DEBUG_FUNCPTR(gst_sbc_enc_dispose);
+
+ element_class->change_state = GST_DEBUG_FUNCPTR(sbc_enc_change_state);
+
+ g_object_class_install_property(object_class, PROP_MODE,
+ g_param_spec_enum("mode", "Mode",
+ "Encoding mode", GST_TYPE_SBC_MODE,
+ SBC_ENC_DEFAULT_MODE, G_PARAM_READWRITE));
+
+ g_object_class_install_property(object_class, PROP_ALLOCATION,
+ g_param_spec_enum("allocation", "Allocation",
+ "Allocation method", GST_TYPE_SBC_ALLOCATION,
+ SBC_ENC_DEFAULT_ALLOCATION, G_PARAM_READWRITE));
+
+ g_object_class_install_property(object_class, PROP_BLOCKS,
+ g_param_spec_enum("blocks", "Blocks",
+ "Blocks", GST_TYPE_SBC_BLOCKS,
+ SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE));
+
+ g_object_class_install_property(object_class, PROP_SUBBANDS,
+ g_param_spec_enum("subbands", "Sub bands",
+ "Number of sub bands", GST_TYPE_SBC_SUBBANDS,
+ SBC_ENC_DEFAULT_SUB_BANDS, G_PARAM_READWRITE));
+
+ g_object_class_install_property(object_class, PROP_BITPOOL,
+ g_param_spec_int("bitpool", "Bitpool",
+ "Bitpool (use 1 for automatic selection)",
+ SBC_ENC_BITPOOL_AUTO, SBC_ENC_BITPOOL_MAX,
+ SBC_ENC_BITPOOL_AUTO, G_PARAM_READWRITE));
+
+ GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0,
+ "SBC encoding element");
+}
+
+static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass)
+{
+ self->sinkpad = gst_pad_new_from_static_template(
+ &sbc_enc_sink_factory, "sink");
+ gst_pad_set_setcaps_function (self->sinkpad,
+ GST_DEBUG_FUNCPTR (sbc_enc_sink_setcaps));
+ gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);
+
+ self->srcpad = gst_pad_new_from_static_template(
+ &sbc_enc_src_factory, "src");
+ gst_pad_set_getcaps_function(self->srcpad,
+ GST_DEBUG_FUNCPTR(sbc_enc_src_getcaps));
+ gst_pad_set_setcaps_function(self->srcpad,
+ GST_DEBUG_FUNCPTR(sbc_enc_src_setcaps));
+ gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
+
+ gst_pad_set_chain_function(self->sinkpad,
+ GST_DEBUG_FUNCPTR(sbc_enc_chain));
+
+ self->subbands = SBC_ENC_DEFAULT_SUB_BANDS;
+ self->blocks = SBC_ENC_DEFAULT_BLOCKS;
+ self->mode = SBC_ENC_DEFAULT_MODE;
+ self->allocation = SBC_ENC_DEFAULT_ALLOCATION;
+ self->rate = SBC_ENC_DEFAULT_RATE;
+ self->channels = SBC_ENC_DEFAULT_CHANNELS;
+ self->bitpool = SBC_ENC_BITPOOL_AUTO;
+
+ self->frame_length = 0;
+ self->frame_duration = 0;
+
+ self->adapter = gst_adapter_new();
+}
+
+gboolean gst_sbc_enc_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "sbcenc",
+ GST_RANK_NONE, GST_TYPE_SBC_ENC);
+}
+
+
diff --git a/utils/audio/gstsbcenc.h b/utils/audio/gstsbcenc.h
new file mode 100644
index 00000000..17e89549
--- /dev/null
+++ b/utils/audio/gstsbcenc.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#include "sbc.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SBC_ENC \
+ (gst_sbc_enc_get_type())
+#define GST_SBC_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_ENC,GstSbcEnc))
+#define GST_SBC_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_ENC,GstSbcEncClass))
+#define GST_IS_SBC_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_ENC))
+#define GST_IS_SBC_ENC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_ENC))
+
+typedef struct _GstSbcEnc GstSbcEnc;
+typedef struct _GstSbcEncClass GstSbcEncClass;
+
+struct _GstSbcEnc {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+ GstAdapter *adapter;
+
+ gint rate;
+ gint channels;
+ gint mode;
+ gint blocks;
+ gint allocation;
+ gint subbands;
+ gint bitpool;
+
+ gint codesize;
+ gint frame_length;
+ gint frame_duration;
+
+ sbc_t sbc;
+};
+
+struct _GstSbcEncClass {
+ GstElementClass parent_class;
+};
+
+GType gst_sbc_enc_get_type(void);
+
+gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin);
+
+G_END_DECLS
diff --git a/utils/audio/gstsbcparse.c b/utils/audio/gstsbcparse.c
new file mode 100644
index 00000000..4521c563
--- /dev/null
+++ b/utils/audio/gstsbcparse.c
@@ -0,0 +1,222 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gstsbcparse.h"
+#include "gstsbcutil.h"
+
+GST_DEBUG_CATEGORY_STATIC(sbc_parse_debug);
+#define GST_CAT_DEFAULT sbc_parse_debug
+
+GST_BOILERPLATE(GstSbcParse, gst_sbc_parse, GstElement, GST_TYPE_ELEMENT);
+
+static const GstElementDetails sbc_parse_details =
+ GST_ELEMENT_DETAILS("Bluetooth SBC parser",
+ "Codec/Parser/Audio",
+ "Parse a SBC audio stream",
+ "Marcel Holtmann <marcel@holtmann.org>");
+
+static GstStaticPadTemplate sbc_parse_sink_factory =
+ GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-sbc,"
+ "parsed = (boolean) false"));
+
+static GstStaticPadTemplate sbc_parse_src_factory =
+ GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("audio/x-sbc, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
+ "blocks = (int) { 4, 8, 12, 16 }, "
+ "subbands = (int) { 4, 8 }, "
+ "allocation = (string) { \"snr\", \"loudness\" },"
+ "bitpool = (int) [ 2, 64 ],"
+ "parsed = (boolean) true"));
+
+static GstFlowReturn sbc_parse_chain(GstPad *pad, GstBuffer *buffer)
+{
+ GstSbcParse *parse = GST_SBC_PARSE(gst_pad_get_parent(pad));
+ GstFlowReturn res = GST_FLOW_OK;
+ guint size, offset = 0;
+ guint8 *data;
+ GstClockTime timestamp;
+
+ timestamp = GST_BUFFER_TIMESTAMP(buffer);
+
+ /* FIXME use a gstadpter */
+ if (parse->buffer) {
+ GstBuffer *temp;
+ temp = buffer;
+ buffer = gst_buffer_span(parse->buffer, 0, buffer,
+ GST_BUFFER_SIZE(parse->buffer)
+ + GST_BUFFER_SIZE(buffer));
+ gst_buffer_unref(parse->buffer);
+ gst_buffer_unref(temp);
+ parse->buffer = NULL;
+ }
+
+ data = GST_BUFFER_DATA(buffer);
+ size = GST_BUFFER_SIZE(buffer);
+
+ while (offset < size) {
+ GstBuffer *output;
+ int consumed;
+
+ consumed = sbc_parse(&parse->new_sbc, data + offset,
+ size - offset);
+ if (consumed <= 0)
+ break;
+
+ if (parse->first_parsing || (memcmp(&parse->sbc,
+ &parse->new_sbc, sizeof(sbc_t)) != 0)) {
+
+ memcpy(&parse->sbc, &parse->new_sbc, sizeof(sbc_t));
+ if (parse->outcaps != NULL)
+ gst_caps_unref(parse->outcaps);
+
+ parse->outcaps = gst_sbc_parse_caps_from_sbc(
+ &parse->sbc);
+
+ parse->first_parsing = FALSE;
+ }
+
+ res = gst_pad_alloc_buffer_and_set_caps(parse->srcpad,
+ GST_BUFFER_OFFSET_NONE,
+ consumed, parse->outcaps, &output);
+
+ if (res != GST_FLOW_OK)
+ goto done;
+
+ memcpy(GST_BUFFER_DATA(output), data + offset, consumed);
+
+ res = gst_pad_push(parse->srcpad, output);
+ if (res != GST_FLOW_OK)
+ goto done;
+
+ offset += consumed;
+ }
+
+ if (offset < size)
+ parse->buffer = gst_buffer_create_sub(buffer,
+ offset, size - offset);
+
+done:
+ gst_buffer_unref(buffer);
+ gst_object_unref(parse);
+
+ return res;
+}
+
+static GstStateChangeReturn sbc_parse_change_state(GstElement *element,
+ GstStateChange transition)
+{
+ GstSbcParse *parse = GST_SBC_PARSE(element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ GST_DEBUG("Setup subband codec");
+
+ parse->channels = -1;
+ parse->rate = -1;
+ parse->first_parsing = TRUE;
+
+ sbc_init(&parse->sbc, 0);
+ break;
+
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_DEBUG("Finish subband codec");
+
+ if (parse->buffer) {
+ gst_buffer_unref(parse->buffer);
+ parse->buffer = NULL;
+ }
+ if (parse->outcaps != NULL) {
+ gst_caps_unref(parse->outcaps);
+ parse->outcaps = NULL;
+ }
+
+ sbc_finish(&parse->sbc);
+ break;
+
+ default:
+ break;
+ }
+
+ return parent_class->change_state(element, transition);
+}
+
+static void gst_sbc_parse_base_init(gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&sbc_parse_sink_factory));
+
+ gst_element_class_add_pad_template(element_class,
+ gst_static_pad_template_get(&sbc_parse_src_factory));
+
+ gst_element_class_set_details(element_class, &sbc_parse_details);
+}
+
+static void gst_sbc_parse_class_init(GstSbcParseClass *klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ element_class->change_state = GST_DEBUG_FUNCPTR(sbc_parse_change_state);
+
+ GST_DEBUG_CATEGORY_INIT(sbc_parse_debug, "sbcparse", 0,
+ "SBC parsing element");
+}
+
+static void gst_sbc_parse_init(GstSbcParse *self, GstSbcParseClass *klass)
+{
+ self->sinkpad = gst_pad_new_from_static_template(
+ &sbc_parse_sink_factory, "sink");
+ gst_pad_set_chain_function(self->sinkpad,
+ GST_DEBUG_FUNCPTR(sbc_parse_chain));
+ gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);
+
+ self->srcpad = gst_pad_new_from_static_template(
+ &sbc_parse_src_factory, "src");
+ gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
+
+ self->outcaps = NULL;
+ self->buffer = NULL;
+ self->channels = -1;
+ self->rate = -1;
+ self->first_parsing = TRUE;
+}
+
+gboolean gst_sbc_parse_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "sbcparse",
+ GST_RANK_NONE, GST_TYPE_SBC_PARSE);
+}
+
diff --git a/utils/audio/gstsbcparse.h b/utils/audio/gstsbcparse.h
new file mode 100644
index 00000000..eceeeea1
--- /dev/null
+++ b/utils/audio/gstsbcparse.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gst/gst.h>
+
+#include "sbc.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SBC_PARSE \
+ (gst_sbc_parse_get_type())
+#define GST_SBC_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_PARSE,GstSbcParse))
+#define GST_SBC_PARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_PARSE,GstSbcParseClass))
+#define GST_IS_SBC_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_PARSE))
+#define GST_IS_SBC_PARSE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_PARSE))
+
+typedef struct _GstSbcParse GstSbcParse;
+typedef struct _GstSbcParseClass GstSbcParseClass;
+
+struct _GstSbcParse {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ GstBuffer *buffer;
+
+ sbc_t sbc;
+ sbc_t new_sbc;
+ GstCaps *outcaps;
+ gboolean first_parsing;
+
+ gint channels;
+ gint rate;
+};
+
+struct _GstSbcParseClass {
+ GstElementClass parent_class;
+};
+
+GType gst_sbc_parse_get_type(void);
+
+gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin);
+
+G_END_DECLS
diff --git a/utils/audio/gstsbcutil.c b/utils/audio/gstsbcutil.c
new file mode 100644
index 00000000..5d646cfb
--- /dev/null
+++ b/utils/audio/gstsbcutil.c
@@ -0,0 +1,521 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include "gstsbcutil.h"
+
+/*
+ * Selects one rate from a list of possible rates
+ * TODO - use a better approach to this (it is selecting the last element)
+ */
+gint gst_sbc_select_rate_from_list(const GValue *value)
+{
+ guint size = gst_value_list_get_size(value);
+ return g_value_get_int(gst_value_list_get_value(value, size-1));
+}
+
+/*
+ * Selects one number of channels option from a range of possible numbers
+ * TODO - use a better approach to this (it is selecting the maximum value)
+ */
+gint gst_sbc_select_channels_from_range(const GValue *value)
+{
+ return gst_value_get_int_range_max(value);
+}
+
+/*
+ * Selects one number of blocks from a list of possible blocks
+ * TODO - use a better approach to this (it is selecting the last element)
+ */
+gint gst_sbc_select_blocks_from_list(const GValue *value)
+{
+ guint size = gst_value_list_get_size(value);
+ return g_value_get_int(gst_value_list_get_value(value, size-1));
+}
+
+/*
+ * Selects one number of subbands from a list
+ * TODO - use a better approach to this (it is selecting the last element)
+ */
+gint gst_sbc_select_subbands_from_list(const GValue *value)
+{
+ guint size = gst_value_list_get_size(value);
+ return g_value_get_int(gst_value_list_get_value(value, size-1));
+}
+
+/*
+ * Selects one bitpool option from a range
+ * TODO - use a better approach to this (it is selecting the maximum value)
+ */
+gint gst_sbc_select_bitpool_from_range(const GValue *value)
+{
+ return gst_value_get_int_range_max(value);
+}
+
+/*
+ * Selects one allocation mode from the ones on the list
+ * TODO - use a better approach
+ */
+const gchar *gst_sbc_get_allocation_from_list(const GValue *value)
+{
+ guint size = gst_value_list_get_size(value);
+ return g_value_get_string(gst_value_list_get_value(value, size-1));
+}
+
+/*
+ * Selects one mode from the ones on the list
+ */
+const gchar *gst_sbc_get_mode_from_list(const GValue *list, gint channels)
+{
+ int i;
+ const GValue *value;
+ const gchar *aux;
+ gboolean joint, stereo, dual, mono;
+
+ joint = stereo = dual = mono = FALSE;
+ guint size = gst_value_list_get_size(list);
+
+ for (i = 0; i < size; i++) {
+ value = gst_value_list_get_value(list, i);
+ aux = g_value_get_string(value);
+ if (strcmp("joint", aux) == 0)
+ joint = TRUE;
+ else if (strcmp("stereo", aux) == 0)
+ stereo = TRUE;
+ else if (strcmp("dual", aux) == 0)
+ dual = TRUE;
+ else if (strcmp("mono", aux) == 0)
+ mono = TRUE;
+ }
+
+ if (channels == 1 && mono)
+ return "mono";
+ else if (channels == 2) {
+ if (joint)
+ return "joint";
+ else if (stereo)
+ return "stereo";
+ else if (dual)
+ return "dual";
+ }
+
+ return NULL;
+}
+
+gint gst_sbc_parse_rate_from_sbc(gint frequency)
+{
+ switch (frequency) {
+ case SBC_FREQ_16000:
+ return 16000;
+ case SBC_FREQ_32000:
+ return 32000;
+ case SBC_FREQ_44100:
+ return 44100;
+ case SBC_FREQ_48000:
+ return 48000;
+ default:
+ return 0;
+ }
+}
+
+gint gst_sbc_parse_rate_to_sbc(gint rate)
+{
+ switch (rate) {
+ case 16000:
+ return SBC_FREQ_16000;
+ case 32000:
+ return SBC_FREQ_32000;
+ case 44100:
+ return SBC_FREQ_44100;
+ case 48000:
+ return SBC_FREQ_48000;
+ default:
+ return -1;
+ }
+}
+
+gint gst_sbc_get_channel_number(gint mode)
+{
+ switch (mode) {
+ case SBC_MODE_JOINT_STEREO:
+ case SBC_MODE_STEREO:
+ case SBC_MODE_DUAL_CHANNEL:
+ return 2;
+ case SBC_MODE_MONO:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+gint gst_sbc_parse_subbands_from_sbc(gint subbands)
+{
+ switch (subbands) {
+ case SBC_SB_4:
+ return 4;
+ case SBC_SB_8:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+gint gst_sbc_parse_subbands_to_sbc(gint subbands)
+{
+ switch (subbands) {
+ case 4:
+ return SBC_SB_4;
+ case 8:
+ return SBC_SB_8;
+ default:
+ return -1;
+ }
+}
+
+gint gst_sbc_parse_blocks_from_sbc(gint blocks)
+{
+ switch (blocks) {
+ case SBC_BLK_4:
+ return 4;
+ case SBC_BLK_8:
+ return 8;
+ case SBC_BLK_12:
+ return 12;
+ case SBC_BLK_16:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+gint gst_sbc_parse_blocks_to_sbc(gint blocks)
+{
+ switch (blocks) {
+ case 4:
+ return SBC_BLK_4;
+ case 8:
+ return SBC_BLK_8;
+ case 12:
+ return SBC_BLK_12;
+ case 16:
+ return SBC_BLK_16;
+ default:
+ return -1;
+ }
+}
+
+const gchar *gst_sbc_parse_mode_from_sbc(gint mode)
+{
+ switch (mode) {
+ case SBC_MODE_MONO:
+ return "mono";
+ case SBC_MODE_DUAL_CHANNEL:
+ return "dual";
+ case SBC_MODE_STEREO:
+ return "stereo";
+ case SBC_MODE_JOINT_STEREO:
+ case SBC_MODE_AUTO:
+ return "joint";
+ default:
+ return NULL;
+ }
+}
+
+gint gst_sbc_parse_mode_to_sbc(const gchar *mode)
+{
+ if (g_ascii_strcasecmp(mode, "joint") == 0)
+ return SBC_MODE_JOINT_STEREO;
+ else if (g_ascii_strcasecmp(mode, "stereo") == 0)
+ return SBC_MODE_STEREO;
+ else if (g_ascii_strcasecmp(mode, "dual") == 0)
+ return SBC_MODE_DUAL_CHANNEL;
+ else if (g_ascii_strcasecmp(mode, "mono") == 0)
+ return SBC_MODE_MONO;
+ else if (g_ascii_strcasecmp(mode, "auto") == 0)
+ return SBC_MODE_JOINT_STEREO;
+ else
+ return -1;
+}
+
+const gchar *gst_sbc_parse_allocation_from_sbc(gint alloc)
+{
+ switch (alloc) {
+ case SBC_AM_LOUDNESS:
+ return "loudness";
+ case SBC_AM_SNR:
+ return "snr";
+ case SBC_AM_AUTO:
+ return "loudness";
+ default:
+ return NULL;
+ }
+}
+
+gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation)
+{
+ if (g_ascii_strcasecmp(allocation, "loudness") == 0)
+ return SBC_AM_LOUDNESS;
+ else if (g_ascii_strcasecmp(allocation, "snr") == 0)
+ return SBC_AM_SNR;
+ else
+ return SBC_AM_LOUDNESS;
+}
+
+GstCaps* gst_sbc_parse_caps_from_sbc(sbc_t *sbc)
+{
+ GstCaps *caps;
+ const gchar *mode_str;
+ const gchar *allocation_str;
+
+ mode_str = gst_sbc_parse_mode_from_sbc(sbc->mode);
+ allocation_str = gst_sbc_parse_allocation_from_sbc(sbc->allocation);
+ caps = gst_caps_new_simple("audio/x-sbc",
+ "rate", G_TYPE_INT,
+ gst_sbc_parse_rate_from_sbc(sbc->frequency),
+ "channels", G_TYPE_INT,
+ gst_sbc_get_channel_number(sbc->mode),
+ "mode", G_TYPE_STRING, mode_str,
+ "subbands", G_TYPE_INT,
+ gst_sbc_parse_subbands_from_sbc(sbc->subbands),
+ "blocks", G_TYPE_INT,
+ gst_sbc_parse_blocks_from_sbc(sbc->blocks),
+ "allocation", G_TYPE_STRING, allocation_str,
+ "bitpool", G_TYPE_INT, sbc->bitpool,
+ NULL);
+
+ return caps;
+}
+
+/*
+ * Given a GstCaps, this will return a fixed GstCaps on sucessfull conversion.
+ * If an error occurs, it will return NULL and error_message will contain the
+ * error message.
+ *
+ * error_message must be passed NULL, if an error occurs, the caller has the
+ * ownership of the error_message, it must be freed after use.
+ */
+GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message)
+{
+ GstCaps *result;
+ GstStructure *structure;
+ const GValue *value;
+ gboolean error = FALSE;
+ gint temp, rate, channels, blocks, subbands, bitpool;
+ const gchar* allocation = NULL;
+ const gchar* mode = NULL;
+
+ g_assert(*error_message == NULL);
+
+ structure = gst_caps_get_structure(caps, 0);
+
+ if (!gst_structure_has_field(structure, "rate")) {
+ error = TRUE;
+ *error_message = g_strdup("no rate");
+ goto error;
+ } else {
+ value = gst_structure_get_value(structure, "rate");
+ if (GST_VALUE_HOLDS_LIST(value))
+ temp = gst_sbc_select_rate_from_list(value);
+ else
+ temp = g_value_get_int(value);
+ rate = temp;
+ }
+
+ if (!gst_structure_has_field(structure, "channels")) {
+ error = TRUE;
+ *error_message = g_strdup("no channels");
+ goto error;
+ } else {
+ value = gst_structure_get_value(structure, "channels");
+ if (GST_VALUE_HOLDS_INT_RANGE(value))
+ temp = gst_sbc_select_channels_from_range(value);
+ else
+ temp = g_value_get_int(value);
+ channels = temp;
+ }
+
+ if (!gst_structure_has_field(structure, "blocks")) {
+ error = TRUE;
+ *error_message = g_strdup("no blocks.");
+ goto error;
+ } else {
+ value = gst_structure_get_value(structure, "blocks");
+ if (GST_VALUE_HOLDS_LIST(value))
+ temp = gst_sbc_select_blocks_from_list(value);
+ else
+ temp = g_value_get_int(value);
+ blocks = temp;
+ }
+
+ if (!gst_structure_has_field(structure, "subbands")) {
+ error = TRUE;
+ *error_message = g_strdup("no subbands");
+ goto error;
+ } else {
+ value = gst_structure_get_value(structure, "subbands");
+ if (GST_VALUE_HOLDS_LIST(value))
+ temp = gst_sbc_select_subbands_from_list(value);
+ else
+ temp = g_value_get_int(value);
+ subbands = temp;
+ }
+
+ if (!gst_structure_has_field(structure, "bitpool")) {
+ error = TRUE;
+ *error_message = g_strdup("no bitpool");
+ goto error;
+ } else {
+ value = gst_structure_get_value(structure, "bitpool");
+ if (GST_VALUE_HOLDS_INT_RANGE(value))
+ temp = gst_sbc_select_bitpool_from_range(value);
+ else
+ temp = g_value_get_int(value);
+ bitpool = temp;
+ }
+
+ if (!gst_structure_has_field(structure, "allocation")) {
+ error = TRUE;
+ *error_message = g_strdup("no allocation");
+ goto error;
+ } else {
+ value = gst_structure_get_value(structure, "allocation");
+ if (GST_VALUE_HOLDS_LIST(value))
+ allocation = gst_sbc_get_allocation_from_list(value);
+ else
+ allocation = g_value_get_string(value);
+ }
+
+ if (!gst_structure_has_field(structure, "mode")) {
+ error = TRUE;
+ *error_message = g_strdup("no mode");
+ goto error;
+ } else {
+ value = gst_structure_get_value(structure, "mode");
+ if (GST_VALUE_HOLDS_LIST(value)) {
+ mode = gst_sbc_get_mode_from_list(value, channels);
+ } else
+ mode = g_value_get_string(value);
+ }
+
+ /* perform validation
+ * if channels is 1, we must have channel mode = mono
+ * if channels is 2, we can't have channel mode = mono */
+ if ( (channels == 1 && (strcmp(mode, "mono") != 0) ) ||
+ ( channels == 2 && ( strcmp(mode, "mono") == 0))) {
+ *error_message = g_strdup_printf("Invalid combination of "
+ "channels (%d) and channel mode (%s)",
+ channels, mode);
+ error = TRUE;
+ }
+
+error:
+ if (error)
+ return NULL;
+
+ result = gst_caps_new_simple("audio/x-sbc",
+ "rate", G_TYPE_INT, rate,
+ "channels", G_TYPE_INT, channels,
+ "mode", G_TYPE_STRING, mode,
+ "blocks", G_TYPE_INT, blocks,
+ "subbands", G_TYPE_INT, subbands,
+ "allocation", G_TYPE_STRING, allocation,
+ "bitpool", G_TYPE_INT, bitpool,
+ NULL);
+
+ return result;
+}
+
+/**
+ * Sets the int field_value to the param "field" on the structure.
+ * value is used to do the operation, it must be a uninitialized (zero-filled)
+ * GValue, it will be left unitialized at the end of the function.
+ */
+void gst_sbc_util_set_structure_int_param(GstStructure *structure,
+ const gchar* field, gint field_value,
+ GValue *value)
+{
+ value = g_value_init(value, G_TYPE_INT);
+ g_value_set_int(value, field_value);
+ gst_structure_set_value(structure, field, value);
+ g_value_unset(value);
+}
+
+/**
+ * Sets the string field_value to the param "field" on the structure.
+ * value is used to do the operation, it must be a uninitialized (zero-filled)
+ * GValue, it will be left unitialized at the end of the function.
+ */
+void gst_sbc_util_set_structure_string_param(GstStructure *structure,
+ const gchar* field, const gchar* field_value,
+ GValue *value)
+{
+ value = g_value_init(value, G_TYPE_STRING);
+ g_value_set_string(value, field_value);
+ gst_structure_set_value(structure, field, value);
+ g_value_unset(value);
+}
+
+gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps)
+{
+ GstStructure *structure;
+ gint rate, channels, subbands, blocks, bitpool;
+ const gchar* mode;
+ const gchar* allocation;
+
+ g_assert(gst_caps_is_fixed(caps));
+
+ structure = gst_caps_get_structure(caps, 0);
+
+ if (!gst_structure_get_int(structure, "rate", &rate))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "channels", &channels))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "subbands", &subbands))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "blocks", &blocks))
+ return FALSE;
+ if (!gst_structure_get_int(structure, "bitpool", &bitpool))
+ return FALSE;
+
+ if (!(mode = gst_structure_get_string(structure, "mode")))
+ return FALSE;
+ if (!(allocation = gst_structure_get_string(structure, "allocation")))
+ return FALSE;
+
+ if (channels == 1 && strcmp(mode, "mono") != 0)
+ return FALSE;
+
+ sbc->frequency = gst_sbc_parse_rate_to_sbc(rate);
+ sbc->blocks = gst_sbc_parse_blocks_to_sbc(blocks);
+ sbc->subbands = gst_sbc_parse_subbands_to_sbc(subbands);
+ sbc->bitpool = bitpool;
+ sbc->mode = gst_sbc_parse_mode_to_sbc(mode);
+ sbc->allocation = gst_sbc_parse_allocation_to_sbc(allocation);
+
+ return TRUE;
+}
+
diff --git a/utils/audio/gstsbcutil.h b/utils/audio/gstsbcutil.h
new file mode 100644
index 00000000..a3cf937c
--- /dev/null
+++ b/utils/audio/gstsbcutil.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gst/gst.h>
+
+#include "sbc.h"
+#include <string.h>
+
+#define SBC_AM_AUTO 0x02
+#define SBC_MODE_AUTO 0x04
+
+gint gst_sbc_select_rate_from_list(const GValue *value);
+
+gint gst_sbc_select_channels_from_range(const GValue *value);
+
+gint gst_sbc_select_blocks_from_list(const GValue *value);
+
+gint gst_sbc_select_subbands_from_list(const GValue *value);
+
+gint gst_sbc_select_bitpool_from_range(const GValue *value);
+
+gint gst_sbc_select_bitpool_from_range(const GValue *value);
+
+const gchar *gst_sbc_get_allocation_from_list(const GValue *value);
+
+const gchar *gst_sbc_get_mode_from_list(const GValue *value, gint channels);
+
+gint gst_sbc_get_channel_number(gint mode);
+gint gst_sbc_parse_rate_from_sbc(gint frequency);
+gint gst_sbc_parse_rate_to_sbc(gint rate);
+
+gint gst_sbc_parse_subbands_from_sbc(gint subbands);
+gint gst_sbc_parse_subbands_to_sbc(gint subbands);
+
+gint gst_sbc_parse_blocks_from_sbc(gint blocks);
+gint gst_sbc_parse_blocks_to_sbc(gint blocks);
+
+const gchar *gst_sbc_parse_mode_from_sbc(gint mode);
+gint gst_sbc_parse_mode_to_sbc(const gchar *mode);
+
+const gchar *gst_sbc_parse_allocation_from_sbc(gint alloc);
+gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation);
+
+GstCaps* gst_sbc_parse_caps_from_sbc(sbc_t *sbc);
+
+GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message);
+
+void gst_sbc_util_set_structure_int_param(GstStructure *structure,
+ const gchar* field, gint field_value,
+ GValue *value);
+
+void gst_sbc_util_set_structure_string_param(GstStructure *structure,
+ const gchar* field, const gchar* field_value,
+ GValue *value);
+
+gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps);
+
diff --git a/utils/audio/headset.c b/utils/audio/headset.c
new file mode 100644
index 00000000..0adc1e9d
--- /dev/null
+++ b/utils/audio/headset.c
@@ -0,0 +1,1924 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "logging.h"
+#include "device.h"
+#include "manager.h"
+#include "error.h"
+#include "headset.h"
+#include "glib-helper.h"
+
+#define DC_TIMEOUT 3000
+
+#define RING_INTERVAL 3000
+
+#define BUF_SIZE 1024
+
+#define HEADSET_GAIN_SPEAKER 'S'
+#define HEADSET_GAIN_MICROPHONE 'M'
+
+#define AG_FEATURE_THREE_WAY_CALLING 0x0001
+#define AG_FEATURE_EC_ANDOR_NR 0x0002
+#define AG_FEATURE_VOICE_RECOGNITION 0x0004
+#define AG_FEATURE_INBAND_RINGTONE 0x0008
+#define AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG 0x0010
+#define AG_FEATURE_REJECT_A_CALL 0x0020
+#define AG_FEATURE_ENHANCES_CALL_STATUS 0x0040
+#define AG_FEATURE_ENHANCES_CALL_CONTROL 0x0080
+#define AG_FEATURE_EXTENDED_ERROR_RESULT_CODES 0x0100
+
+static uint32_t ag_features = 0;
+
+static gboolean sco_hci = TRUE;
+
+static char *str_state[] = {
+ "HEADSET_STATE_DISCONNECTED",
+ "HEADSET_STATE_CONNECT_IN_PROGRESS",
+ "HEADSET_STATE_CONNECTED",
+ "HEADSET_STATE_PLAY_IN_PROGRESS",
+ "HEADSET_STATE_PLAYING",
+};
+
+struct connect_cb {
+ unsigned int id;
+ headset_stream_cb_t cb;
+ void *cb_data;
+};
+
+struct pending_connect {
+ DBusMessage *msg;
+ DBusPendingCall *call;
+ GIOChannel *io;
+ int err;
+ headset_state_t target_state;
+ GSList *callbacks;
+};
+
+struct headset {
+ uint32_t hsp_handle;
+ uint32_t hfp_handle;
+
+ int rfcomm_ch;
+
+ GIOChannel *rfcomm;
+ GIOChannel *tmp_rfcomm;
+ GIOChannel *sco;
+ guint sco_id;
+
+ gboolean auto_dc;
+
+ guint ring_timer;
+
+ guint dc_timer;
+
+ char buf[BUF_SIZE];
+ int data_start;
+ int data_length;
+
+ gboolean hfp_active;
+ gboolean search_hfp;
+ gboolean cli_active;
+ char *ph_number;
+ int type;
+
+ headset_state_t state;
+ struct pending_connect *pending;
+
+ int sp_gain;
+ int mic_gain;
+
+ unsigned int hfp_features;
+ headset_lock_t lock;
+};
+
+struct event {
+ const char *cmd;
+ int (*callback) (struct audio_device *device, const char *buf);
+};
+
+static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb,
+ void *user_data, unsigned int *cb_id);
+static int get_records(struct audio_device *device, headset_stream_cb_t cb,
+ void *user_data, unsigned int *cb_id);
+
+static int headset_send(struct headset *hs, char *format, ...)
+{
+ char rsp[BUF_SIZE];
+ va_list ap;
+ ssize_t total_written, written, count;
+ int fd;
+
+ va_start(ap, format);
+ count = vsnprintf(rsp, sizeof(rsp), format, ap);
+ va_end(ap);
+
+ if (count < 0)
+ return -EINVAL;
+
+ if (!hs->rfcomm) {
+ error("headset_send: the headset is not connected");
+ return -EIO;
+ }
+
+ written = total_written = 0;
+ fd = g_io_channel_unix_get_fd(hs->rfcomm);
+
+ while (total_written < count) {
+ written = write(fd, rsp + total_written, count - total_written);
+ if (written < 0)
+ return -errno;
+
+ total_written += written;
+ }
+
+ return 0;
+}
+
+static int supported_features(struct audio_device *device, const char *buf)
+{
+ struct headset *hs = device->headset;
+ int err;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ hs->hfp_features = strtoul(&buf[8], NULL, 10);
+ err = headset_send(hs, "\r\n+BRSF=%u\r\n", ag_features);
+ if (err < 0)
+ return err;
+
+ return headset_send(hs, "\r\nOK\r\n");
+}
+
+static int report_indicators(struct audio_device *device, const char *buf)
+{
+ struct headset *hs = device->headset;
+ int err;
+
+ if (buf[7] == '=')
+ err = headset_send(hs, "\r\n+CIND:(\"service\",(0,1)),"
+ "(\"call\",(0,1)),(\"callsetup\",(0-3))\r\n");
+ else
+ err = headset_send(hs, "\r\n+CIND:1,0,0\r\n");
+
+ if (err < 0)
+ return err;
+
+ return headset_send(hs, "\r\nOK\r\n");
+}
+
+static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ if (hs->pending->err)
+ cb->cb(NULL, cb->cb_data);
+ else
+ cb->cb(dev, cb->cb_data);
+}
+
+static void pending_connect_finalize(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+ struct pending_connect *p = hs->pending;
+
+ g_slist_foreach(p->callbacks, (GFunc) pending_connect_complete, dev);
+
+ g_slist_foreach(p->callbacks, (GFunc) g_free, NULL);
+ g_slist_free(p->callbacks);
+
+ if (p->io) {
+ g_io_channel_close(p->io);
+ g_io_channel_unref(p->io);
+ }
+
+ if (p->msg)
+ dbus_message_unref(p->msg);
+
+ if (p->call) {
+ dbus_pending_call_cancel(p->call);
+ dbus_pending_call_unref(p->call);
+ }
+
+ g_free(p);
+
+ hs->pending = NULL;
+}
+
+static void pending_connect_init(struct headset *hs, headset_state_t target_state)
+{
+ if (hs->pending) {
+ if (hs->pending->target_state < target_state)
+ hs->pending->target_state = target_state;
+ return;
+ }
+
+ hs->pending = g_new0(struct pending_connect, 1);
+ hs->pending->target_state = target_state;
+}
+
+static unsigned int connect_cb_new(struct headset *hs,
+ headset_state_t target_state,
+ headset_stream_cb_t func,
+ void *user_data)
+{
+ struct connect_cb *cb;
+ unsigned int free_cb_id = 1;
+
+ pending_connect_init(hs, target_state);
+
+ cb = g_new(struct connect_cb, 1);
+
+ cb->cb = func;
+ cb->cb_data = user_data;
+ cb->id = free_cb_id++;
+
+ hs->pending->callbacks = g_slist_append(hs->pending->callbacks,
+ cb);
+
+ return cb->id;
+}
+
+static void sco_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ int sk;
+ struct audio_device *dev = user_data;
+ struct headset *hs = dev->headset;
+ struct pending_connect *p = hs->pending;
+
+ if (err < 0) {
+ error("connect(): %s (%d)", strerror(-err), -err);
+
+ 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);
+ else
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+
+ return;
+ }
+
+ debug("SCO socket opened for headset %s", dev->path);
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ info("SCO fd=%d", sk);
+ hs->sco = chan;
+ p->io = NULL;
+
+ if (p->msg) {
+ DBusMessage *reply = dbus_message_new_method_return(p->msg);
+ dbus_connection_send(dev->conn, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+ pending_connect_finalize(dev);
+
+ fcntl(sk, F_SETFL, 0);
+
+ headset_set_state(dev, HEADSET_STATE_PLAYING);
+}
+
+static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
+ void *user_data, unsigned int *cb_id)
+{
+ struct headset *hs = dev->headset;
+ int err;
+
+ if (hs->state != HEADSET_STATE_CONNECTED)
+ return -EINVAL;
+
+ err = bt_sco_connect(&dev->src, &dev->dst, sco_connect_cb, dev);
+ if (err < 0) {
+ error("connect: %s (%d)", strerror(-err), -err);
+ return -err;
+ }
+
+ headset_set_state(dev, HEADSET_STATE_PLAY_IN_PROGRESS);
+
+ pending_connect_init(hs, HEADSET_STATE_PLAYING);
+
+ if (cb) {
+ unsigned int id = connect_cb_new(hs, HEADSET_STATE_PLAYING,
+ cb, user_data);
+ if (cb_id)
+ *cb_id = id;
+ }
+
+ return 0;
+}
+
+static void hfp_slc_complete(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+ struct pending_connect *p = hs->pending;
+
+ debug("HFP Service Level Connection established");
+
+ headset_set_state(dev, HEADSET_STATE_CONNECTED);
+
+ if (p == NULL)
+ return;
+
+ if (p->msg) {
+ DBusMessage *reply = dbus_message_new_method_return(p->msg);
+ dbus_connection_send(dev->conn, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+ if (p->target_state == HEADSET_STATE_CONNECTED) {
+ pending_connect_finalize(dev);
+ return;
+ }
+
+ p->err = sco_connect(dev, NULL, NULL, NULL);
+ if (p->err < 0)
+ pending_connect_finalize(dev);
+}
+
+static int event_reporting(struct audio_device *dev, const char *buf)
+{
+ struct headset *hs = dev->headset;
+ int ret;
+
+ ret = headset_send(hs, "\r\nOK\r\n");
+ if (ret < 0)
+ return ret;
+
+ if (hs->state != HEADSET_STATE_CONNECT_IN_PROGRESS)
+ return 0;
+
+ if (ag_features & AG_FEATURE_THREE_WAY_CALLING)
+ return 0;
+
+ hfp_slc_complete(dev);
+
+ return 0;
+}
+
+static int call_hold(struct audio_device *dev, const char *buf)
+{
+ struct headset *hs = dev->headset;
+ int err;
+
+ err = headset_send(hs, "\r\n+CHLD:(0,1,1x,2,2x,3,4)\r\n");
+ if (err < 0)
+ return err;
+
+ err = headset_send(hs, "\r\nOK\r\n");
+ if (err < 0)
+ return err;
+
+ if (hs->state != HEADSET_STATE_CONNECT_IN_PROGRESS)
+ return 0;
+
+ hfp_slc_complete(dev);
+
+ return 0;
+}
+
+static int answer_call(struct audio_device *device, const char *buf)
+{
+ struct headset *hs = device->headset;
+ int err;
+
+ g_dbus_emit_signal(device->conn, device->path,
+ AUDIO_HEADSET_INTERFACE, "AnswerRequested",
+ DBUS_TYPE_INVALID);
+
+ if (hs->ring_timer) {
+ g_source_remove(hs->ring_timer);
+ hs->ring_timer = 0;
+ }
+
+ if (!hs->hfp_active)
+ return headset_send(hs, "\r\nOK\r\n");
+
+ if (hs->ph_number) {
+ g_free(hs->ph_number);
+ hs->ph_number = NULL;
+ }
+
+ err = headset_send(hs, "\r\nOK\r\n");
+ if (err < 0)
+ return err;
+
+ /*+CIEV: (call = 1)*/
+ err = headset_send(hs, "\r\n+CIEV:2,1\r\n");
+ if (err < 0)
+ return err;
+
+ /*+CIEV: (callsetup = 0)*/
+ return headset_send(hs, "\r\n+CIEV:3,0\r\n");
+}
+
+static int terminate_call(struct audio_device *device, const char *buf)
+{
+ struct headset *hs = device->headset;
+ int err;
+
+ g_dbus_emit_signal(device->conn, device->path,
+ AUDIO_HEADSET_INTERFACE, "CallTerminated",
+ DBUS_TYPE_INVALID);
+
+ err = headset_send(hs, "\r\nOK\r\n");
+ if (err < 0)
+ return err;
+
+ if (hs->ph_number) {
+ g_free(hs->ph_number);
+ hs->ph_number = NULL;
+ }
+
+ if (hs->ring_timer) {
+ g_source_remove(hs->ring_timer);
+ hs->ring_timer = 0;
+ /*+CIEV: (callsetup = 0)*/
+ return headset_send(hs, "\r\n+CIEV:3,0\r\n");
+ }
+
+ /*+CIEV: (call = 0)*/
+ return headset_send(hs, "\r\n+CIEV:2,0\r\n");
+}
+
+static int cli_notification(struct audio_device *device, const char *buf)
+{
+ struct headset *hs = device->headset;
+
+ if (strlen(buf) < 9)
+ return -EINVAL;
+
+ hs->cli_active = buf[8] == '1' ? TRUE : FALSE;
+
+ return headset_send(hs, "\r\nOK\r\n");
+}
+
+static int signal_gain_setting(struct audio_device *device, const char *buf)
+{
+ struct headset *hs = device->headset;
+ 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);
+
+ if (gain > 15) {
+ error("Invalid gain value received: %u", gain);
+ return -EINVAL;
+ }
+
+ switch (buf[5]) {
+ case HEADSET_GAIN_SPEAKER:
+ if (hs->sp_gain == gain)
+ goto ok;
+ name = "SpeakerGainChanged";
+ hs->sp_gain = gain;
+ break;
+ case HEADSET_GAIN_MICROPHONE:
+ if (hs->mic_gain == gain)
+ goto ok;
+ name = "MicrophoneGainChanged";
+ hs->mic_gain = gain;
+ break;
+ default:
+ error("Unknown gain setting");
+ return -EINVAL;
+ }
+
+ g_dbus_emit_signal(device->conn, device->path,
+ AUDIO_HEADSET_INTERFACE, name,
+ DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+
+ok:
+ return headset_send(hs, "\r\nOK\r\n");
+}
+
+static struct event event_callbacks[] = {
+ { "ATA", answer_call },
+ { "AT+VG", signal_gain_setting },
+ { "AT+BRSF", supported_features },
+ { "AT+CIND", report_indicators },
+ { "AT+CMER", event_reporting },
+ { "AT+CHLD", call_hold },
+ { "AT+CHUP", terminate_call },
+ { "AT+CKPD", answer_call },
+ { "AT+CLIP", cli_notification },
+ { 0 }
+};
+
+static int handle_event(struct audio_device *device, const char *buf)
+{
+ struct event *ev;
+
+ debug("Received %s", buf);
+
+ for (ev = event_callbacks; ev->cmd; ev++) {
+ if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
+ return ev->callback(device, buf);
+ }
+
+ return -EINVAL;
+}
+
+static void close_sco(struct audio_device *device)
+{
+ struct headset *hs = device->headset;
+
+ if (hs->sco) {
+ g_source_remove(hs->sco_id);
+ hs->sco_id = 0;
+ g_io_channel_close(hs->sco);
+ g_io_channel_unref(hs->sco);
+ hs->sco = NULL;
+ }
+}
+
+static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
+ struct audio_device *device)
+{
+ struct headset *hs;
+ unsigned char buf[BUF_SIZE];
+ char *cr;
+ gsize bytes_read = 0;
+ gsize free_space;
+ int err;
+ off_t cmd_len;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ hs = device->headset;
+
+ if (cond & (G_IO_ERR | G_IO_HUP))
+ goto failed;
+
+ if (g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1,
+ &bytes_read) != G_IO_ERROR_NONE)
+ return TRUE;
+
+ free_space = sizeof(hs->buf) - hs->data_start - hs->data_length - 1;
+
+ if (free_space < bytes_read) {
+ /* Very likely that the HS is sending us garbage so
+ * just ignore the data and disconnect */
+ error("Too much data to fit incomming buffer");
+ goto failed;
+ }
+
+ memcpy(&hs->buf[hs->data_start], buf, bytes_read);
+ hs->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';
+
+ cr = strchr(&hs->buf[hs->data_start], '\r');
+ if (!cr)
+ return TRUE;
+
+ cmd_len = 1 + (off_t) cr - (off_t) &hs->buf[hs->data_start];
+ *cr = '\0';
+
+ err = handle_event(device, &hs->buf[hs->data_start]);
+ if (err == -EINVAL) {
+ error("Badly formated or unrecognized command: %s",
+ &hs->buf[hs->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], strerror(-err), -err);
+
+ hs->data_start += cmd_len;
+ hs->data_length -= cmd_len;
+
+ if (!hs->data_length)
+ hs->data_start = 0;
+
+ return TRUE;
+
+failed:
+ headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+
+static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
+ struct audio_device *device)
+{
+ struct headset *hs;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ hs = device->headset;
+
+ error("Audio connection got disconnected");
+
+ headset_set_state(device, HEADSET_STATE_CONNECTED);
+
+ return FALSE;
+}
+
+static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct audio_device *dev = user_data;
+ struct headset *hs = dev->headset;
+ struct pending_connect *p = hs->pending;
+ char hs_address[18];
+
+ if (err < 0) {
+ error("connect(): %s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ ba2str(&dev->dst, hs_address);
+ hs->rfcomm = chan;
+ p->io = NULL;
+
+ if (server_is_enabled(HANDSFREE_SVCLASS_ID) && hs->hfp_handle != 0)
+ hs->hfp_active = TRUE;
+ else
+ hs->hfp_active = FALSE;
+
+ 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);
+
+ /* In HFP mode wait for Service Level Connection */
+ if (hs->hfp_active)
+ return;
+
+ headset_set_state(dev, HEADSET_STATE_CONNECTED);
+
+ if (p->target_state == HEADSET_STATE_PLAYING) {
+ p->err = sco_connect(dev, NULL, NULL, NULL);
+ if (p->err < 0)
+ goto failed;
+ return;
+ }
+
+ if (p->msg) {
+ DBusMessage *reply = dbus_message_new_method_return(p->msg);
+ dbus_connection_send(dev->conn, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+ pending_connect_finalize(dev);
+
+ return;
+
+failed:
+ 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);
+ else
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+}
+
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct audio_device *dev = user_data;
+ struct headset *hs = dev->headset;
+ struct pending_connect *p = hs->pending;
+ int ch = -1;
+ sdp_record_t *record = NULL;
+ sdp_list_t *protos, *classes = NULL;
+ uuid_t uuid;
+
+ if (err < 0) {
+ error("Unable to get service record: %s (%d)", strerror(-err),
+ -err);
+ goto failed_not_supported;
+ }
+
+ if (!recs || !recs->data) {
+ error("No records found");
+ goto failed_not_supported;
+ }
+
+ record = recs->data;
+
+ if (sdp_get_service_classes(record, &classes) < 0) {
+ error("Unable to get service classes from record");
+ goto failed_not_supported;
+ }
+
+ memcpy(&uuid, classes->data, sizeof(uuid));
+
+ if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16) {
+ error("Not a 16 bit UUID");
+ goto failed_not_supported;
+ }
+
+ if (hs->search_hfp) {
+ if (uuid.value.uuid16 != HANDSFREE_SVCLASS_ID) {
+ error("Service record didn't contain the HFP UUID");
+ goto failed_not_supported;
+ }
+ hs->hfp_handle = record->handle;
+ } else {
+ if (uuid.value.uuid16 != HEADSET_SVCLASS_ID) {
+ error("Service record didn't contain the HSP UUID");
+ goto failed_not_supported;
+ }
+ hs->hsp_handle = record->handle;
+ }
+
+ if (!sdp_get_access_protos(record, &protos)) {
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
+ NULL);
+ sdp_list_free(protos, NULL);
+ protos = NULL;
+ }
+
+ if (ch == -1) {
+ error("Unable to extract RFCOMM channel from service record");
+ goto failed_not_supported;
+ }
+
+ hs->rfcomm_ch = ch;
+
+ err = rfcomm_connect(dev, NULL, NULL, NULL);
+ if (err < 0) {
+ error("Unable to connect: %s (%s)", strerror(-err), -err);
+ p->err = -err;
+ error_connection_attempt_failed(dev->conn, p->msg, p->err);
+ goto failed;
+ }
+
+ sdp_list_free(classes, free);
+ sdp_record_free(record);
+
+ return;
+
+failed_not_supported:
+ if (p->msg) {
+ error_not_supported(dev->conn, p->msg);
+ dbus_message_unref(p->msg);
+ p->msg = NULL;
+ }
+failed:
+ if (classes)
+ sdp_list_free(classes, free);
+ if (record)
+ sdp_record_free(record);
+ pending_connect_finalize(dev);
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+}
+
+static int get_records(struct audio_device *device, headset_stream_cb_t cb,
+ void *user_data, unsigned int *cb_id)
+{
+ struct headset *hs = device->headset;
+ uuid_t uuid;
+
+ sdp_uuid16_create(&uuid, hs->search_hfp ? HANDSFREE_SVCLASS_ID :
+ HEADSET_SVCLASS_ID);
+
+ headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);
+
+ pending_connect_init(hs, HEADSET_STATE_CONNECTED);
+
+ if (cb) {
+ unsigned int id;
+ id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,
+ cb, user_data);
+ if (cb_id)
+ *cb_id = id;
+ }
+
+ return bt_search_service(&device->src, &device->dst, &uuid,
+ get_record_cb, device, NULL);
+}
+
+static int rfcomm_connect(struct audio_device *dev, headset_stream_cb_t cb,
+ void *user_data, unsigned int *cb_id)
+{
+ struct headset *hs = dev->headset;
+ char address[18];
+ int err;
+
+ if (hs->rfcomm_ch < 0)
+ return get_records(dev, cb, user_data, cb_id);
+
+ ba2str(&dev->dst, address);
+
+ debug("%s: Connecting to %s channel %d", dev->path, address,
+ hs->rfcomm_ch);
+
+ err = bt_rfcomm_connect(&dev->src, &dev->dst, hs->rfcomm_ch,
+ rfcomm_connect_cb, dev);
+ if (err < 0) {
+ error("connect() failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ headset_set_state(dev, HEADSET_STATE_CONNECT_IN_PROGRESS);
+
+ pending_connect_init(hs, HEADSET_STATE_CONNECTED);
+
+ if (cb) {
+ unsigned int id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,
+ cb, user_data);
+ if (cb_id)
+ *cb_id = id;
+ }
+
+ return 0;
+}
+
+static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply = NULL;
+
+ if (hs->state < HEADSET_STATE_PLAY_IN_PROGRESS)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ headset_set_state(device, HEADSET_STATE_CONNECTED);
+
+ return reply;
+}
+
+static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ dbus_bool_t playing;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ playing = (hs->state == HEADSET_STATE_PLAYING);
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply = NULL;
+ char hs_address[18];
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (hs->state == HEADSET_STATE_DISCONNECTED)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+ ba2str(&device->dst, hs_address);
+ info("Disconnected from %s, %s", hs_address, device->path);
+
+ return reply;
+}
+
+static DBusMessage *hs_is_connected(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ DBusMessage *reply;
+ dbus_bool_t connected;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ connected = (device->headset->state >= HEADSET_STATE_CONNECTED);
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ int err;
+
+ if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",
+ "Connect in Progress");
+ else if (hs->state > HEADSET_STATE_CONNECT_IN_PROGRESS)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".AlreadyConnected",
+ "Already Connected");
+
+ err = rfcomm_connect(device, NULL, NULL, NULL);
+ if (err < 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".ConnectAttemptFailed",
+ "Connect Attempt Failed");
+
+ hs->auto_dc = FALSE;
+
+ hs->pending->msg = dbus_message_ref(msg);
+
+ return NULL;
+}
+
+static gboolean ring_timer_cb(gpointer data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ int err;
+
+ err = headset_send(hs, "\r\nRING\r\n");
+
+ if (err < 0)
+ error("Error while sending RING: %s (%d)",
+ strerror(-err), -err);
+
+ if (hs->cli_active && hs->ph_number) {
+ err = headset_send(hs, "\r\n+CLIP:\"%s\",%d\r\n",
+ hs->ph_number, hs->type);
+
+ if (err < 0)
+ error("Error while sending CLIP: %s (%d)",
+ strerror(-err), -err);
+ }
+
+ return TRUE;
+}
+
+static DBusMessage *hs_ring(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply = NULL;
+ int err;
+
+ if (hs->state < HEADSET_STATE_CONNECTED)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (hs->ring_timer) {
+ debug("IndicateCall received when already indicating");
+ goto done;
+ }
+
+ err = headset_send(hs, "\r\nRING\r\n");
+ if (err < 0) {
+ dbus_message_unref(reply);
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", strerror(-err));
+ }
+
+ if (hs->cli_active && hs->ph_number) {
+ err = headset_send(hs, "\r\n+CLIP:\"%s\",%d\r\n",
+ hs->ph_number, hs->type);
+ if (err < 0) {
+ dbus_message_unref(reply);
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed", "%s",
+ strerror(-err));
+ }
+ }
+
+ hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);
+
+done:
+ return reply;
+}
+
+static DBusMessage *hs_cancel_ringing(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply = NULL;
+
+ if (hs->state < HEADSET_STATE_CONNECTED)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (!hs->ring_timer) {
+ debug("Got CancelRinging method call but ringing is not in progress");
+ goto done;
+ }
+
+ g_source_remove(hs->ring_timer);
+ hs->ring_timer = 0;
+
+done:
+ if (hs->hfp_active) {
+ int err;
+ /*+CIEV: (callsetup = 0)*/
+ err = headset_send(hs, "\r\n+CIEV:3,0\r\n");
+ if (err < 0) {
+ dbus_message_unref(reply);
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".Failed", "%s",
+ strerror(-err));
+ }
+ }
+
+ return reply;
+}
+
+static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ int err;
+
+ if (sco_hci) {
+ error("Refusing Headset.Play() because SCO HCI routing "
+ "is enabled");
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
+ "Operation not Available");
+ }
+
+ switch (hs->state) {
+ case HEADSET_STATE_DISCONNECTED:
+ case HEADSET_STATE_CONNECT_IN_PROGRESS:
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+ case HEADSET_STATE_PLAY_IN_PROGRESS:
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".InProgress",
+ "Play in Progress");
+ case HEADSET_STATE_PLAYING:
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".AlreadyConnected",
+ "Device Already Connected");
+ case HEADSET_STATE_CONNECTED:
+ default:
+ break;
+ }
+
+ err = sco_connect(device, NULL, NULL, NULL);
+ if (err < 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", strerror(-err));
+
+ hs->pending->msg = dbus_message_ref(msg);
+
+ return NULL;
+}
+
+static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ dbus_uint16_t gain;
+
+ if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
+ "Operation not Available");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ gain = (dbus_uint16_t) hs->sp_gain;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ dbus_uint16_t gain;
+
+ if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
+ "Operation not Available");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ gain = (dbus_uint16_t) hs->mic_gain;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *hs_set_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data, char type)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ dbus_uint16_t gain;
+ int err;
+
+ if (hs->state < HEADSET_STATE_CONNECTED)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (gain > 15)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".InvalidArgument",
+ "Must be less than or equal to 15");
+
+ reply = dbus_message_new_method_return(msg);
+ 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",
+ "%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;
+}
+
+static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ return hs_set_gain(conn, msg, data, HEADSET_GAIN_SPEAKER);
+}
+
+static DBusMessage *hs_set_mic_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ return hs_set_gain(conn, msg, data, HEADSET_GAIN_MICROPHONE);
+}
+
+static DBusMessage *hf_setup_call(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ const char *value;
+ int err;
+
+ if (!hs->hfp_active)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotSuppported",
+ "Not Supported");
+
+ if (hs->state < HEADSET_STATE_CONNECTED)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &value,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (!strncmp(value, "incoming", 8))
+ err = headset_send(hs, "\r\n+CIEV:3,1\r\n");
+ else if (!strncmp(value, "outgoing", 8))
+ err = headset_send(hs, "\r\n+CIEV:3,2\r\n");
+ else if (!strncmp(value, "remote", 6))
+ err = headset_send(hs, "\r\n+CIEV:3,3\r\n");
+ else
+ err = -EINVAL;
+
+ if (err < 0) {
+ dbus_message_unref(reply);
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", strerror(-err));
+ }
+
+ return reply;
+}
+
+static DBusMessage *hf_identify_call(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ const char *number;
+ dbus_int32_t type;
+
+ if (!hs->hfp_active && !hs->cli_active)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotSuppported",
+ "Not Supported");
+
+ if (hs->state < HEADSET_STATE_CONNECTED)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
+ DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID))
+ return NULL;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ g_free(hs->ph_number);
+
+ hs->ph_number = g_strdup(number);
+ hs->type = type;
+
+ return reply;
+}
+
+static GDBusMethodTable headset_methods[] = {
+ { "Connect", "", "", hs_connect,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "Disconnect", "", "", hs_disconnect },
+ { "IsConnected", "", "b", hs_is_connected },
+ { "IndicateCall", "", "", hs_ring },
+ { "CancelCall", "", "", hs_cancel_ringing },
+ { "Play", "", "", hs_play,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "Stop", "", "", hs_stop },
+ { "IsPlaying", "", "b", hs_is_playing },
+ { "GetSpeakerGain", "", "q", hs_get_speaker_gain },
+ { "GetMicrophoneGain", "", "q", hs_get_mic_gain },
+ { "SetSpeakerGain", "q", "", hs_set_speaker_gain },
+ { "SetMicrophoneGain", "q", "", hs_set_mic_gain },
+ { "SetupCall", "s", "", hf_setup_call },
+ { "IdentifyCall", "si", "", hf_identify_call },
+ { NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable headset_signals[] = {
+ { "Connected", "" },
+ { "Disconnected", "" },
+ { "AnswerRequested", "" },
+ { "Stopped", "" },
+ { "Playing", "" },
+ { "SpeakerGainChanged", "q" },
+ { "MicrophoneGainChanged", "q" },
+ { "CallTerminated", "" },
+ { NULL, NULL }
+};
+
+static void headset_set_channel(struct headset *headset, sdp_record_t *record,
+ uint16_t svc)
+{
+ int ch;
+ sdp_list_t *protos;
+
+ if (sdp_get_access_protos(record, &protos) < 0) {
+ error("Unable to get access protos from headset record");
+ return;
+ }
+
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+
+ if (ch > 0) {
+ headset->rfcomm_ch = ch;
+ debug("Discovered %s service on RFCOMM channel %d",
+ svc == HEADSET_SVCLASS_ID ? "Headset" : "Handsfree",
+ ch);
+ } else
+ error("Unable to get RFCOMM channel from Headset record");
+}
+
+void headset_update(struct audio_device *dev, sdp_record_t *record, uint16_t svc)
+{
+ struct headset *headset = dev->headset;
+
+ switch (svc) {
+ case HANDSFREE_SVCLASS_ID:
+ if (headset->hfp_handle &&
+ (headset->hfp_handle != record->handle)) {
+ error("More than one HFP record found on device");
+ return;
+ }
+
+ headset->hfp_handle = record->handle;
+ break;
+
+ case HEADSET_SVCLASS_ID:
+ if (headset->hsp_handle &&
+ (headset->hsp_handle != record->handle)) {
+ error("More than one HSP record found on device");
+ return;
+ }
+
+ headset->hsp_handle = record->handle;
+
+ /* Ignore this record if we already have access to HFP */
+ if (headset->hfp_handle)
+ return;
+
+ break;
+
+ default:
+ debug("Invalid record passed to headset_update");
+ return;
+ }
+
+ headset_set_channel(headset, record, svc);
+}
+
+struct headset *headset_init(struct audio_device *dev, sdp_record_t *record,
+ uint16_t svc)
+{
+ struct headset *hs;
+
+ hs = g_new0(struct headset, 1);
+ hs->rfcomm_ch = -1;
+ hs->sp_gain = -1;
+ hs->mic_gain = -1;
+ hs->search_hfp = server_is_enabled(HANDSFREE_SVCLASS_ID);
+ hs->hfp_active = FALSE;
+ hs->cli_active = FALSE;
+ hs->ph_number = NULL;
+
+ if (!record)
+ goto register_iface;
+
+ switch (svc) {
+ case HANDSFREE_SVCLASS_ID:
+ hs->hfp_handle = record->handle;
+ break;
+
+ case HEADSET_SVCLASS_ID:
+ hs->hsp_handle = record->handle;
+ break;
+
+ default:
+ debug("Invalid record passed to headset_init");
+ g_free(hs);
+ return NULL;
+ }
+
+ headset_set_channel(hs, record, svc);
+register_iface:
+ if (!g_dbus_register_interface(dev->conn, dev->path,
+ AUDIO_HEADSET_INTERFACE,
+ headset_methods, headset_signals, NULL,
+ dev, NULL)) {
+ g_free(hs);
+ return NULL;
+ }
+
+ return hs;
+}
+
+uint32_t headset_config_init(GKeyFile *config)
+{
+ GError *err = NULL;
+ gboolean value;
+ char *str;
+
+ /* Use the default values if there is no config file */
+ if (config == NULL)
+ return ag_features;
+
+ str = g_key_file_get_string(config, "General", "SCORouting",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ if (strcmp(str, "PCM") == 0)
+ sco_hci = FALSE;
+ else if (strcmp(str, "HCI") == 0)
+ sco_hci = TRUE;
+ else
+ error("Invalid Headset Routing value: %s", str);
+ g_free(str);
+ }
+
+ value = g_key_file_get_boolean(config, "Headset", "3WayCalling",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_THREE_WAY_CALLING;
+
+ value = g_key_file_get_boolean(config, "Headset", "EchoCancelNoiseCancel",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_EC_ANDOR_NR;
+
+ value = g_key_file_get_boolean(config, "Headset", "VoiceRecognition",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_VOICE_RECOGNITION;
+
+ value = g_key_file_get_boolean(config, "Headset", "InBandRingtone",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_INBAND_RINGTONE;
+
+ value = g_key_file_get_boolean(config, "Headset", "VoiceTags",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG;
+
+ value = g_key_file_get_boolean(config, "Headset", "RejectingCalls",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_REJECT_A_CALL;
+
+ value = g_key_file_get_boolean(config, "Headset", "EnhancedCallStatus",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_ENHANCES_CALL_STATUS;
+
+ value = g_key_file_get_boolean(config, "Headset", "EnhancedCallControl",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_ENHANCES_CALL_CONTROL;
+
+ value = g_key_file_get_boolean(config, "Headset",
+ "ExtendedErrorResultCodes", &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else if (value)
+ ag_features |= AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
+
+ return ag_features;
+}
+
+void headset_free(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ if (hs->dc_timer) {
+ g_source_remove(hs->dc_timer);
+ hs->dc_timer = 0;
+ }
+
+ if (hs->sco) {
+ g_io_channel_close(hs->sco);
+ g_io_channel_unref(hs->sco);
+ }
+
+ if (hs->rfcomm) {
+ g_io_channel_close(hs->rfcomm);
+ g_io_channel_unref(hs->rfcomm);
+ }
+
+ g_free(hs);
+ dev->headset = NULL;
+}
+
+static gboolean hs_dc_timeout(struct audio_device *dev)
+{
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+ return FALSE;
+}
+
+gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id)
+{
+ struct headset *hs = dev->headset;
+ struct pending_connect *p = hs->pending;
+ GSList *l;
+ struct connect_cb *cb = NULL;
+
+ if (!p)
+ return FALSE;
+
+ for (l = p->callbacks; l != NULL; l = l->next) {
+ struct connect_cb *tmp = l->data;
+
+ if (tmp->id == id) {
+ cb = tmp;
+ break;
+ }
+ }
+
+ if (!cb)
+ return FALSE;
+
+ p->callbacks = g_slist_remove(p->callbacks, cb);
+ g_free(cb);
+
+ if (p->callbacks || p->msg)
+ return TRUE;
+
+ pending_connect_finalize(dev);
+
+ if (hs->auto_dc) {
+ if (hs->rfcomm)
+ hs->dc_timer = g_timeout_add(DC_TIMEOUT,
+ (GSourceFunc) hs_dc_timeout,
+ dev);
+ else
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+ }
+
+ return TRUE;
+}
+
+static gboolean dummy_connect_complete(struct audio_device *dev)
+{
+ pending_connect_finalize(dev);
+ return FALSE;
+}
+
+unsigned int headset_request_stream(struct audio_device *dev, headset_stream_cb_t cb,
+ void *user_data)
+{
+ struct headset *hs = dev->headset;
+ unsigned int id;
+
+ if (hs->rfcomm && hs->sco) {
+ id = connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
+ g_idle_add((GSourceFunc) dummy_connect_complete, dev);
+ return id;
+ }
+
+ if (hs->dc_timer) {
+ g_source_remove(hs->dc_timer);
+ hs->dc_timer = 0;
+ }
+
+ if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)
+ return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
+
+ if (hs->rfcomm == NULL) {
+ if (rfcomm_connect(dev, cb, user_data, &id) < 0)
+ return 0;
+ hs->auto_dc = TRUE;
+ } else {
+ if (sco_connect(dev, cb, user_data, &id) < 0)
+ return 0;
+ }
+
+ hs->pending->target_state = HEADSET_STATE_PLAYING;
+
+ return id;
+}
+
+gboolean get_hfp_active(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ return hs->hfp_active;
+}
+
+void set_hfp_active(struct audio_device *dev, gboolean active)
+{
+ struct headset *hs = dev->headset;
+
+ hs->hfp_active = active;
+}
+
+int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
+{
+ struct headset *hs = dev->headset;
+
+ hs->tmp_rfcomm = io;
+
+ return hs->tmp_rfcomm ? 0 : -EINVAL;
+}
+
+int headset_close_rfcomm(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+ GIOChannel *rfcomm = hs->tmp_rfcomm ? hs->tmp_rfcomm : hs->rfcomm;
+
+ if (hs->ring_timer) {
+ g_source_remove(hs->ring_timer);
+ hs->ring_timer = 0;
+ }
+
+ if (rfcomm) {
+ g_io_channel_close(rfcomm);
+ g_io_channel_unref(rfcomm);
+ hs->tmp_rfcomm = NULL;
+ hs->rfcomm = NULL;
+ }
+
+ hs->data_start = 0;
+ hs->data_length = 0;
+
+ return 0;
+}
+
+void headset_set_authorized(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ hs->rfcomm = hs->tmp_rfcomm;
+ hs->tmp_rfcomm = NULL;
+
+ g_io_add_watch(hs->rfcomm,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc) rfcomm_io_cb, dev);
+
+ hs->auto_dc = FALSE;
+
+ if (!hs->hfp_active)
+ headset_set_state(dev, HEADSET_STATE_CONNECTED);
+}
+
+void headset_set_state(struct audio_device *dev, headset_state_t state)
+{
+ struct headset *hs = dev->headset;
+
+ if (hs->state == state)
+ return;
+
+ switch (state) {
+ case HEADSET_STATE_DISCONNECTED:
+ close_sco(dev);
+ headset_close_rfcomm(dev);
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_HEADSET_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+ break;
+ case HEADSET_STATE_CONNECT_IN_PROGRESS:
+ break;
+ case HEADSET_STATE_CONNECTED:
+ close_sco(dev);
+ if (hs->state < state) {
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_HEADSET_INTERFACE,
+ "Connected",
+ DBUS_TYPE_INVALID);
+ } else if (hs->state == HEADSET_STATE_PLAYING) {
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_HEADSET_INTERFACE,
+ "Stopped",
+ DBUS_TYPE_INVALID);
+ }
+ break;
+ case HEADSET_STATE_PLAY_IN_PROGRESS:
+ break;
+ case HEADSET_STATE_PLAYING:
+ hs->sco_id = g_io_add_watch(hs->sco,
+ G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) sco_cb, dev);
+
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_HEADSET_INTERFACE,
+ "Playing", DBUS_TYPE_INVALID);
+
+ 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);
+ break;
+ }
+
+ debug("State changed %s: %s -> %s", dev->path, str_state[hs->state],
+ str_state[state]);
+ hs->state = state;
+}
+
+headset_state_t headset_get_state(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ return hs->state;
+}
+
+int headset_get_channel(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ return hs->rfcomm_ch;
+}
+
+gboolean headset_is_active(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ if (hs->state != HEADSET_STATE_DISCONNECTED)
+ return TRUE;
+
+ return FALSE;
+}
+
+gboolean headset_lock(struct audio_device *dev, headset_lock_t lock)
+{
+ struct headset *hs = dev->headset;
+
+ if (hs->lock & lock)
+ return FALSE;
+
+ hs->lock |= lock;
+
+ return TRUE;
+}
+
+gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock)
+{
+ struct headset *hs = dev->headset;
+
+ if (!(hs->lock & lock))
+ return FALSE;
+
+ hs->lock &= ~lock;
+
+ if (hs->lock)
+ return TRUE;
+
+ if (hs->state == HEADSET_STATE_PLAYING)
+ headset_set_state(dev, HEADSET_STATE_CONNECTED);
+
+ if (hs->auto_dc) {
+ if (hs->state == HEADSET_STATE_CONNECTED)
+ hs->dc_timer = g_timeout_add(DC_TIMEOUT,
+ (GSourceFunc) hs_dc_timeout,
+ dev);
+ else
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+ }
+
+ return TRUE;
+}
+
+gboolean headset_suspend(struct audio_device *dev, void *data)
+{
+ return TRUE;
+}
+
+gboolean headset_play(struct audio_device *dev, void *data)
+{
+ return TRUE;
+}
+
+int headset_get_sco_fd(struct audio_device *dev)
+{
+ struct headset *hs = dev->headset;
+
+ if (!hs->sco)
+ return -1;
+
+ return g_io_channel_unix_get_fd(hs->sco);
+}
diff --git a/utils/audio/headset.h b/utils/audio/headset.h
new file mode 100644
index 00000000..b61a1015
--- /dev/null
+++ b/utils/audio/headset.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define AUDIO_HEADSET_INTERFACE "org.bluez.audio.Headset"
+
+#define DEFAULT_HS_AG_CHANNEL 12
+#define DEFAULT_HF_AG_CHANNEL 13
+
+typedef enum {
+ HEADSET_STATE_DISCONNECTED,
+ HEADSET_STATE_CONNECT_IN_PROGRESS,
+ HEADSET_STATE_CONNECTED,
+ HEADSET_STATE_PLAY_IN_PROGRESS,
+ HEADSET_STATE_PLAYING
+} headset_state_t;
+
+typedef enum {
+ HEADSET_LOCK_READ = 1,
+ HEADSET_LOCK_WRITE = 1 << 1,
+} headset_lock_t;
+
+typedef void (*headset_stream_cb_t) (struct audio_device *dev, void *user_data);
+
+struct headset *headset_init(struct audio_device *dev, sdp_record_t *record,
+ uint16_t svc);
+
+void headset_free(struct audio_device *dev);
+
+uint32_t headset_config_init(GKeyFile *config);
+
+void headset_update(struct audio_device *dev, sdp_record_t *record, uint16_t svc);
+
+unsigned int headset_request_stream(struct audio_device *dev,
+ headset_stream_cb_t cb, void *user_data);
+gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id);
+
+gboolean get_hfp_active(struct audio_device *dev);
+void set_hfp_active(struct audio_device *dev, gboolean active);
+
+void headset_set_authorized(struct audio_device *dev);
+int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *chan);
+int headset_close_rfcomm(struct audio_device *dev);
+
+headset_state_t headset_get_state(struct audio_device *dev);
+void headset_set_state(struct audio_device *dev, headset_state_t state);
+
+int headset_get_channel(struct audio_device *dev);
+
+int headset_get_sco_fd(struct audio_device *dev);
+
+gboolean headset_is_active(struct audio_device *dev);
+
+gboolean headset_lock(struct audio_device *dev, headset_lock_t lock);
+gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock);
+gboolean headset_suspend(struct audio_device *dev, void *data);
+gboolean headset_play(struct audio_device *dev, void *data);
diff --git a/utils/audio/ipc.c b/utils/audio/ipc.c
new file mode 100644
index 00000000..e7b712da
--- /dev/null
+++ b/utils/audio/ipc.c
@@ -0,0 +1,119 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "ipc.h"
+
+/* This table contains the string representation for messages */
+static const char *strmsg[] = {
+ "BT_GETCAPABILITIES_REQ",
+ "BT_GETCAPABILITIES_RSP",
+ "BT_SETCONFIGURATION_REQ",
+ "BT_SETCONFIGURATION_RSP",
+ "BT_STREAMSTART_REQ",
+ "BT_STREAMSTART_RSP",
+ "BT_STREAMSTOP_REQ",
+ "BT_STREAMSTOP_RSP",
+ "BT_STREAMSUSPEND_IND",
+ "BT_STREAMRESUME_IND",
+ "BT_CONTROL_REQ",
+ "BT_CONTROL_RSP",
+ "BT_CONTROL_IND",
+ "BT_STREAMFD_IND",
+};
+
+int bt_audio_service_open()
+{
+ int sk;
+ int err;
+ struct sockaddr_un addr = {
+ AF_UNIX, BT_IPC_SOCKET_NAME
+ };
+
+ sk = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = errno;
+ fprintf(stderr, "%s: Cannot open socket: %s (%d)\n",
+ __FUNCTION__, strerror(err), err);
+ errno = err;
+ return -1;
+ }
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ fprintf(stderr, "%s: connect() failed: %s (%d)\n",
+ __FUNCTION__, strerror(err), err);
+ close(sk);
+ errno = err;
+ return -1;
+ }
+
+ return sk;
+}
+
+int bt_audio_service_close(int sk)
+{
+ return close(sk);
+}
+
+int bt_audio_service_get_data_fd(int sk)
+{
+ char cmsg_b[CMSG_SPACE(sizeof(int))], m;
+ int err, ret;
+ struct iovec iov = { &m, sizeof(m) };
+ struct msghdr msgh;
+ struct cmsghdr *cmsg;
+
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = &cmsg_b;
+ msgh.msg_controllen = CMSG_LEN(sizeof(int));
+
+ ret = recvmsg(sk, &msgh, 0);
+ if (ret < 0) {
+ err = errno;
+ fprintf(stderr, "%s: Unable to receive fd: %s (%d)\n",
+ __FUNCTION__, strerror(err), err);
+ errno = err;
+ return -1;
+ }
+
+ /* Receive auxiliary data in msgh */
+ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == SCM_RIGHTS)
+ return (*(int *) CMSG_DATA(cmsg));
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+const char *bt_audio_strmsg(int type)
+{
+ if (type < 0 || type > (sizeof(strmsg) / sizeof(strmsg[0])))
+ return NULL;
+
+ return strmsg[type];
+}
+
diff --git a/utils/audio/ipc.h b/utils/audio/ipc.h
new file mode 100644
index 00000000..c900fcd1
--- /dev/null
+++ b/utils/audio/ipc.h
@@ -0,0 +1,308 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/*
+ Message sequence chart of streaming sequence for A2DP transport
+
+ Audio daemon User
+ on snd_pcm_open
+ <--BT_GETCAPABILITIES_REQ
+
+ BT_GETCAPABILITIES_RSP-->
+
+ on snd_pcm_hw_params
+ <--BT_SETCONFIGURATION_REQ
+
+ BT_SETCONFIGURATION_RSP-->
+
+ on snd_pcm_prepare
+ <--BT_STREAMSTART_REQ
+
+ <Moves to streaming state>
+ BT_STREAMSTART_RSP-->
+
+ BT_STREAMFD_IND -->
+
+ < streams data >
+ ..........
+
+ on snd_pcm_drop/snd_pcm_drain
+
+ <--BT_STREAMSTOP_REQ
+
+ <Moves to open state>
+ BT_STREAMSTOP_RSP-->
+
+ on IPC close or appl crash
+ <Moves to idle>
+
+ */
+
+#ifndef BT_AUDIOCLIENT_H
+#define BT_AUDIOCLIENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#define BT_AUDIO_IPC_PACKET_SIZE 128
+#define BT_IPC_SOCKET_NAME "\0/org/bluez/audio"
+
+/* Generic message header definition, except for RSP messages */
+typedef struct {
+ uint8_t msg_type;
+} __attribute__ ((packed)) bt_audio_msg_header_t;
+
+/* Generic message header definition, for all RSP messages */
+typedef struct {
+ bt_audio_msg_header_t msg_h;
+ uint8_t posix_errno;
+} __attribute__ ((packed)) bt_audio_rsp_msg_header_t;
+
+/* Messages list */
+#define BT_GETCAPABILITIES_REQ 0
+#define BT_GETCAPABILITIES_RSP 1
+
+#define BT_SETCONFIGURATION_REQ 2
+#define BT_SETCONFIGURATION_RSP 3
+
+#define BT_STREAMSTART_REQ 4
+#define BT_STREAMSTART_RSP 5
+
+#define BT_STREAMSTOP_REQ 6
+#define BT_STREAMSTOP_RSP 7
+
+#define BT_STREAMSUSPEND_IND 8
+#define BT_STREAMRESUME_IND 9
+
+#define BT_CONTROL_REQ 10
+#define BT_CONTROL_RSP 11
+#define BT_CONTROL_IND 12
+
+#define BT_STREAMFD_IND 13
+
+/* BT_GETCAPABILITIES_REQ */
+
+#define BT_CAPABILITIES_TRANSPORT_A2DP 0
+#define BT_CAPABILITIES_TRANSPORT_SCO 1
+#define BT_CAPABILITIES_TRANSPORT_ANY 2
+
+#define BT_CAPABILITIES_ACCESS_MODE_READ 1
+#define BT_CAPABILITIES_ACCESS_MODE_WRITE 2
+#define BT_CAPABILITIES_ACCESS_MODE_READWRITE 3
+
+#define BT_FLAG_AUTOCONNECT 1
+
+struct bt_getcapabilities_req {
+ bt_audio_msg_header_t h;
+ char device[18]; /* Address of the remote Device */
+ uint8_t transport; /* Requested transport */
+ uint8_t flags; /* Requested flags */
+} __attribute__ ((packed));
+
+/* BT_GETCAPABILITIES_RSP */
+
+/**
+ * SBC Codec parameters as per A2DP profile 1.0 § 4.3
+ */
+
+#define BT_SBC_SAMPLING_FREQ_16000 (1 << 3)
+#define BT_SBC_SAMPLING_FREQ_32000 (1 << 2)
+#define BT_SBC_SAMPLING_FREQ_44100 (1 << 1)
+#define BT_SBC_SAMPLING_FREQ_48000 1
+
+#define BT_A2DP_CHANNEL_MODE_MONO (1 << 3)
+#define BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define BT_A2DP_CHANNEL_MODE_STEREO (1 << 1)
+#define BT_A2DP_CHANNEL_MODE_JOINT_STEREO 1
+
+#define BT_A2DP_BLOCK_LENGTH_4 (1 << 3)
+#define BT_A2DP_BLOCK_LENGTH_8 (1 << 2)
+#define BT_A2DP_BLOCK_LENGTH_12 (1 << 1)
+#define BT_A2DP_BLOCK_LENGTH_16 1
+
+#define BT_A2DP_SUBBANDS_4 (1 << 1)
+#define BT_A2DP_SUBBANDS_8 1
+
+#define BT_A2DP_ALLOCATION_SNR (1 << 1)
+#define BT_A2DP_ALLOCATION_LOUDNESS 1
+
+#define BT_MPEG_SAMPLING_FREQ_16000 (1 << 5)
+#define BT_MPEG_SAMPLING_FREQ_22050 (1 << 4)
+#define BT_MPEG_SAMPLING_FREQ_24000 (1 << 3)
+#define BT_MPEG_SAMPLING_FREQ_32000 (1 << 2)
+#define BT_MPEG_SAMPLING_FREQ_44100 (1 << 1)
+#define BT_MPEG_SAMPLING_FREQ_48000 1
+
+#define BT_MPEG_LAYER_1 (1 << 2)
+#define BT_MPEG_LAYER_2 (1 << 1)
+#define BT_MPEG_LAYER_3 1
+
+typedef struct {
+ uint8_t channel_mode;
+ uint8_t frequency;
+ uint8_t allocation_method;
+ uint8_t subbands;
+ uint8_t block_length;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed)) sbc_capabilities_t;
+
+typedef struct {
+ uint8_t channel_mode;
+ uint8_t crc;
+ uint8_t layer;
+ uint8_t frequency;
+ uint8_t mpf;
+ uint16_t bitrate;
+} __attribute__ ((packed)) mpeg_capabilities_t;
+
+struct bt_getcapabilities_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+ uint8_t transport; /* Granted transport */
+ sbc_capabilities_t sbc_capabilities; /* A2DP only */
+ mpeg_capabilities_t mpeg_capabilities; /* A2DP only */
+ uint16_t sampling_rate; /* SCO only */
+} __attribute__ ((packed));
+
+/* BT_SETCONFIGURATION_REQ */
+struct bt_setconfiguration_req {
+ bt_audio_msg_header_t h;
+ char device[18]; /* Address of the remote Device */
+ uint8_t transport; /* Requested transport */
+ uint8_t access_mode; /* Requested access mode */
+ sbc_capabilities_t sbc_capabilities; /* A2DP only - only one of this field
+ and next one must be filled */
+ mpeg_capabilities_t mpeg_capabilities; /* A2DP only */
+} __attribute__ ((packed));
+
+/* BT_SETCONFIGURATION_RSP */
+struct bt_setconfiguration_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+ uint8_t transport; /* Granted transport */
+ uint8_t access_mode; /* Granted access mode */
+ uint16_t link_mtu; /* Max length that transport supports */
+} __attribute__ ((packed));
+
+/* BT_STREAMSTART_REQ */
+#define BT_STREAM_ACCESS_READ 0
+#define BT_STREAM_ACCESS_WRITE 1
+#define BT_STREAM_ACCESS_READWRITE 2
+struct bt_streamstart_req {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSTART_RSP */
+struct bt_streamstart_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+} __attribute__ ((packed));
+
+/* BT_STREAMFD_IND */
+/* This message is followed by one byte of data containing the stream data fd
+ as ancilliary data */
+struct bt_streamfd_ind {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSTOP_REQ */
+struct bt_streamstop_req {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSTOP_RSP */
+struct bt_streamstop_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSUSPEND_IND */
+struct bt_streamsuspend_ind {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMRESUME_IND */
+struct bt_streamresume_ind {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_CONTROL_REQ */
+
+#define BT_CONTROL_KEY_POWER 0x40
+#define BT_CONTROL_KEY_VOL_UP 0x41
+#define BT_CONTROL_KEY_VOL_DOWN 0x42
+#define BT_CONTROL_KEY_MUTE 0x43
+#define BT_CONTROL_KEY_PLAY 0x44
+#define BT_CONTROL_KEY_STOP 0x45
+#define BT_CONTROL_KEY_PAUSE 0x46
+#define BT_CONTROL_KEY_RECORD 0x47
+#define BT_CONTROL_KEY_REWIND 0x48
+#define BT_CONTROL_KEY_FAST_FORWARD 0x49
+#define BT_CONTROL_KEY_EJECT 0x4A
+#define BT_CONTROL_KEY_FORWARD 0x4B
+#define BT_CONTROL_KEY_BACKWARD 0x4C
+
+struct bt_control_req {
+ bt_audio_msg_header_t h;
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
+} __attribute__ ((packed));
+
+/* BT_CONTROL_RSP */
+struct bt_control_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
+} __attribute__ ((packed));
+
+/* BT_CONTROL_IND */
+struct bt_control_ind {
+ bt_audio_msg_header_t h;
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
+} __attribute__ ((packed));
+
+/* Function declaration */
+
+/* Opens a connection to the audio service: return a socket descriptor */
+int bt_audio_service_open();
+
+/* Closes a connection to the audio service */
+int bt_audio_service_close(int sk);
+
+/* Receives stream data file descriptor : must be called after a
+BT_STREAMFD_IND message is returned */
+int bt_audio_service_get_data_fd(int sk);
+
+/* Human readable message type string */
+const char *bt_audio_strmsg(int type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BT_AUDIOCLIENT_H */
diff --git a/utils/audio/main.c b/utils/audio/main.c
new file mode 100644
index 00000000..607e3ca9
--- /dev/null
+++ b/utils/audio/main.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "plugin.h"
+#include "../hcid/device.h"
+#include "logging.h"
+#include "unix.h"
+#include "device.h"
+#include "manager.h"
+
+static DBusConnection *conn;
+
+static int headset_probe(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ return 0;
+}
+
+static void headset_remove(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+}
+
+static struct btd_device_driver headset_driver = {
+ .name = "headset",
+ .uuids = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID),
+ .probe = headset_probe,
+ .remove = headset_remove,
+};
+
+static int a2dp_probe(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ return 0;
+}
+
+static void a2dp_remove(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+}
+
+static struct btd_device_driver a2dp_driver = {
+ .name = "sink",
+ .uuids = BTD_UUIDS(A2DP_SINK_UUID),
+ .probe = a2dp_probe,
+ .remove = a2dp_remove,
+};
+
+static int audio_probe(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ return 0;
+}
+
+static void audio_remove(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+}
+
+static struct btd_device_driver audio_driver = {
+ .name = "audio",
+ .uuids = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID,
+ ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID,
+ AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID),
+ .probe = audio_probe,
+ .remove = audio_remove,
+};
+
+
+static GKeyFile *load_config_file(const char *file)
+{
+ GError *err = NULL;
+ GKeyFile *keyfile;
+
+ 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_error_free(err);
+ g_key_file_free(keyfile);
+ return NULL;
+ }
+
+ return keyfile;
+}
+
+static int audio_init(void)
+{
+ GKeyFile *config;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (conn == NULL)
+ return -EIO;
+
+ config = load_config_file(CONFIGDIR "/audio.conf");
+
+ if (unix_init() < 0) {
+ error("Unable to setup unix socket");
+ return -EIO;
+ }
+
+ if (audio_manager_init(conn, config) < 0) {
+ dbus_connection_unref(conn);
+ return -EIO;
+ }
+
+ if (config)
+ g_key_file_free(config);
+
+ btd_register_device_driver(&headset_driver);
+
+ btd_register_device_driver(&a2dp_driver);
+
+ btd_register_device_driver(&audio_driver);
+
+ return 0;
+}
+
+static void audio_exit(void)
+{
+ btd_unregister_device_driver(&audio_driver);
+
+ btd_unregister_device_driver(&a2dp_driver);
+
+ btd_unregister_device_driver(&headset_driver);
+
+ audio_manager_exit();
+
+ unix_exit();
+
+ dbus_connection_unref(conn);
+}
+
+BLUETOOTH_PLUGIN_DEFINE("audio", audio_init, audio_exit)
diff --git a/utils/audio/manager.c b/utils/audio/manager.c
new file mode 100644
index 00000000..18ef9eb4
--- /dev/null
+++ b/utils/audio/manager.c
@@ -0,0 +1,1571 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "glib-helper.h"
+
+#include "dbus-service.h"
+#include "logging.h"
+#include "textfile.h"
+#include "ipc.h"
+#include "device.h"
+#include "error.h"
+#include "avdtp.h"
+#include "a2dp.h"
+#include "headset.h"
+#include "gateway.h"
+#include "sink.h"
+#include "control.h"
+#include "manager.h"
+#include "sdpd.h"
+
+typedef enum {
+ HEADSET = 1 << 0,
+ GATEWAY = 1 << 1,
+ SINK = 1 << 2,
+ SOURCE = 1 << 3,
+ CONTROL = 1 << 4,
+ TARGET = 1 << 5,
+ INVALID = 1 << 6
+} audio_service_type;
+
+typedef enum {
+ GENERIC_AUDIO = 0,
+ ADVANCED_AUDIO,
+ AV_REMOTE,
+ GET_RECORDS
+} audio_sdp_state_t;
+
+struct audio_sdp_data {
+ struct audio_device *device;
+
+ DBusMessage *msg; /* Method call or NULL */
+
+ GSList *records; /* sdp_record_t * */
+
+ audio_sdp_state_t state;
+
+ create_dev_cb_t cb;
+ void *cb_data;
+};
+
+static DBusConnection *connection = NULL;
+
+static struct audio_device *default_hs = NULL;
+static struct audio_device *default_dev = NULL;
+
+static GSList *devices = NULL;
+
+static uint32_t hsp_ag_record_id = 0;
+static uint32_t hfp_ag_record_id = 0;
+
+static uint32_t hsp_hs_record_id = 0;
+
+static GIOChannel *hsp_ag_server = NULL;
+static GIOChannel *hfp_ag_server = NULL;
+
+static GIOChannel *hsp_hs_server = NULL;
+
+static struct enabled_interfaces enabled = {
+ .headset = TRUE,
+ .gateway = FALSE,
+ .sink = TRUE,
+ .source = FALSE,
+ .control = TRUE,
+};
+
+static DBusMessage *get_records(uuid_t *uuid, struct audio_sdp_data *data);
+
+static struct audio_device *create_device(const bdaddr_t *bda)
+{
+ static int device_id = 0;
+ char path[128];
+
+ snprintf(path, sizeof(path) - 1,
+ "%s/device%d", AUDIO_MANAGER_PATH, device_id++);
+
+ return device_register(connection, path, bda);
+}
+
+static void destroy_device(struct audio_device *device)
+{
+ g_dbus_unregister_all_interfaces(connection, device->path);
+}
+
+static void remove_device(struct audio_device *device)
+{
+ if (device == default_dev) {
+ debug("Removing default device");
+ default_dev = NULL;
+ }
+
+ if (device == default_hs) {
+ debug("Removing default headset");
+ default_hs = NULL;
+ }
+
+ devices = g_slist_remove(devices, device);
+
+ destroy_device(device);
+}
+
+static gboolean add_device(struct audio_device *device, gboolean send_signals)
+{
+ if (!send_signals)
+ goto add;
+
+ g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DeviceCreated",
+ DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+
+ if (device->headset)
+ g_dbus_emit_signal(connection,
+ AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "HeadsetCreated",
+ DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+add:
+
+ if (default_dev == NULL && g_slist_length(devices) == 0) {
+ debug("Selecting default device");
+ default_dev = device;
+ }
+
+ if (!default_hs && device->headset && !devices)
+ default_hs = device;
+
+ devices = g_slist_append(devices, device);
+
+ return TRUE;
+}
+
+static uint16_t get_service_uuid(const sdp_record_t *record)
+{
+ sdp_list_t *classes;
+ uuid_t uuid;
+ uint16_t uuid16 = 0;
+
+ if (sdp_get_service_classes(record, &classes) < 0) {
+ error("Unable to get service classes from record");
+ return 0;
+ }
+
+ memcpy(&uuid, classes->data, sizeof(uuid));
+
+ if (!sdp_uuid128_to_uuid(&uuid)) {
+ error("Not a 16 bit UUID");
+ sdp_list_free(classes, free);
+ return 0;
+ }
+
+ if (uuid.type == SDP_UUID32) {
+ if (uuid.value.uuid32 > 0xFFFF) {
+ error("Not a 16 bit UUID");
+ goto done;
+ }
+ uuid16 = (uint16_t) uuid.value.uuid32;
+ } else
+ uuid16 = uuid.value.uuid16;
+
+done:
+ sdp_list_free(classes, free);
+
+ return uuid16;
+}
+
+gboolean server_is_enabled(uint16_t svc)
+{
+ gboolean ret;
+
+ switch (svc) {
+ case HEADSET_SVCLASS_ID:
+ ret = (hsp_ag_server != NULL);
+ break;
+ case HEADSET_AGW_SVCLASS_ID:
+ ret = (hsp_hs_server != NULL);
+ break;
+ case HANDSFREE_SVCLASS_ID:
+ ret = (hfp_ag_server != NULL);
+ break;
+ case HANDSFREE_AGW_SVCLASS_ID:
+ ret = FALSE;
+ break;
+ case AUDIO_SINK_SVCLASS_ID:
+ return enabled.sink;
+ case AV_REMOTE_TARGET_SVCLASS_ID:
+ case AV_REMOTE_SVCLASS_ID:
+ return enabled.control;
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ return ret;
+}
+
+static void handle_record(sdp_record_t *record, struct audio_device *device)
+{
+ gboolean is_default;
+ uint16_t uuid16;
+
+ uuid16 = get_service_uuid(record);
+
+ if (!server_is_enabled(uuid16))
+ return;
+
+ switch (uuid16) {
+ case HEADSET_SVCLASS_ID:
+ debug("Found Headset record");
+ if (device->headset)
+ headset_update(device, record, uuid16);
+ else
+ device->headset = headset_init(device,
+ record, uuid16);
+ break;
+ case HEADSET_AGW_SVCLASS_ID:
+ debug("Found Headset AG record");
+ break;
+ case HANDSFREE_SVCLASS_ID:
+ debug("Found Hansfree record");
+ if (device->headset)
+ headset_update(device, record, uuid16);
+ else
+ device->headset = headset_init(device,
+ record, uuid16);
+ break;
+ case HANDSFREE_AGW_SVCLASS_ID:
+ debug("Found Handsfree AG record");
+ break;
+ case AUDIO_SINK_SVCLASS_ID:
+ debug("Found Audio Sink");
+ if (device->sink == NULL)
+ device->sink = sink_init(device);
+ break;
+ case AUDIO_SOURCE_SVCLASS_ID:
+ debug("Found Audio Source");
+ break;
+ case AV_REMOTE_SVCLASS_ID:
+ debug("Found AV Remote");
+ if (device->control == NULL)
+ device->control = control_init(device);
+ if (device->sink && sink_is_active(device))
+ avrcp_connect(device);
+ break;
+ case AV_REMOTE_TARGET_SVCLASS_ID:
+ debug("Found AV Target");
+ if (device->control == NULL)
+ device->control = control_init(device);
+ if (device->sink && sink_is_active(device))
+ avrcp_connect(device);
+ break;
+ default:
+ debug("Unrecognized UUID: 0x%04X", uuid16);
+ break;
+ }
+
+ is_default = (default_dev == device) ? TRUE : FALSE;
+
+ device_store(device, is_default);
+}
+
+static void finish_sdp(struct audio_sdp_data *data, gboolean success)
+{
+ const char *addr;
+ DBusMessage *reply = NULL;
+ DBusError derr;
+
+ debug("Audio service discovery completed with %s",
+ success ? "success" : "failure");
+
+ if (!success)
+ goto done;
+
+ if (!data->msg)
+ goto update;
+
+ dbus_error_init(&derr);
+ dbus_message_get_args(data->msg, &derr,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_error_is_set(&derr)) {
+ error("Unable to get message args");
+ success = FALSE;
+ error_failed(connection, data->msg, derr.message);
+ dbus_error_free(&derr);
+ goto done;
+ }
+
+ /* Return error if no audio related service records were found */
+ if (!data->records) {
+ debug("No audio audio related service records were found");
+ success = FALSE;
+ error_not_supported(connection, data->msg);
+ goto done;
+ }
+
+ reply = dbus_message_new_method_return(data->msg);
+ if (!reply) {
+ success = FALSE;
+ error_failed(connection, data->msg, "Out of memory");
+ goto done;
+ }
+
+update:
+ g_slist_foreach(data->records, (GFunc) handle_record, data->device);
+
+ if (!g_slist_find(devices, data->device))
+ add_device(data->device, TRUE);
+
+ if (reply) {
+ dbus_message_append_args(reply, DBUS_TYPE_STRING,
+ &data->device->path,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+done:
+ if (success) {
+ if (data->cb)
+ data->cb(data->device, data->cb_data);
+ } else {
+ if (data->cb)
+ data->cb(NULL, data->cb_data);
+ if (!g_slist_find(devices, data->device))
+ destroy_device(data->device);
+ }
+ if (data->msg)
+ dbus_message_unref(data->msg);
+ g_slist_foreach(data->records, (GFunc) sdp_record_free, NULL);
+ g_slist_free(data->records);
+ g_free(data);
+}
+
+static void get_records_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct audio_sdp_data *data = user_data;
+ sdp_list_t *seq;
+ uuid_t uuid;
+
+ if (err < 0) {
+ error_connection_attempt_failed(connection, data->msg, -err);
+ finish_sdp(data, FALSE);
+ return;
+ }
+
+ for (seq = recs; seq; seq = seq->next) {
+ sdp_record_t *rec = (sdp_record_t *) seq->data;
+
+ if (!rec)
+ break;
+
+ data->records = g_slist_append(data->records, rec);
+ }
+
+ sdp_list_free(recs, NULL);
+
+ data->state++;
+
+ switch (data->state) {
+ case ADVANCED_AUDIO:
+ sdp_uuid16_create(&uuid, ADVANCED_AUDIO_SVCLASS_ID);
+ break;
+ case AV_REMOTE:
+ sdp_uuid16_create(&uuid, AV_REMOTE_SVCLASS_ID);
+ break;
+ default:
+ finish_sdp(data, TRUE);
+ return;
+ }
+
+ get_records(&uuid, data);
+}
+
+static DBusMessage *get_records(uuid_t *uuid, struct audio_sdp_data *data)
+{
+ struct audio_device *device = data->device;
+ DBusMessage *reply = NULL;
+ int err;
+
+ err = bt_search_service(&device->src, &device->dst, uuid,
+ get_records_cb, data, NULL);
+ if (!err)
+ return NULL;
+
+ if (data->msg)
+ reply = g_dbus_create_error(data->msg,
+ ERROR_INTERFACE ".ConnectionAttemptFailed",
+ strerror(-err));
+
+ finish_sdp(data, FALSE);
+
+ return reply;
+}
+
+static DBusMessage *resolve_services(DBusMessage *msg,
+ struct audio_device *device,
+ create_dev_cb_t cb,
+ void *user_data)
+{
+ struct audio_sdp_data *sdp_data;
+ uuid_t uuid;
+
+ sdp_data = g_new0(struct audio_sdp_data, 1);
+ if (msg)
+ sdp_data->msg = dbus_message_ref(msg);
+ sdp_data->device = device;
+ sdp_data->cb = cb;
+ sdp_data->cb_data = user_data;
+
+ sdp_uuid16_create(&uuid, GENERIC_AUDIO_SVCLASS_ID);
+
+ return get_records(&uuid, sdp_data);
+}
+
+struct audio_device *manager_device_connected(const bdaddr_t *bda, const char *uuid)
+{
+ struct audio_device *device;
+ const char *path;
+ gboolean headset = FALSE, created = FALSE;
+
+ device = manager_find_device(bda, NULL, FALSE);
+ if (!device) {
+ device = create_device(bda);
+ if (!device)
+ return NULL;
+ if (!add_device(device, TRUE)) {
+ destroy_device(device);
+ return NULL;
+ }
+ created = TRUE;
+ }
+
+ if (!strcmp(uuid, HSP_AG_UUID) || !strcmp(uuid, HFP_AG_UUID)) {
+ if (device->headset)
+ return device;
+
+ device->headset = headset_init(device, NULL, 0);
+
+ if (!device->headset)
+ return NULL;
+
+ headset = TRUE;
+ } else if (!strcmp(uuid, A2DP_SOURCE_UUID)) {
+ if (device->sink)
+ return device;
+
+ device->sink = sink_init(device);
+
+ if (!device->sink)
+ return NULL;
+ } else if (!strcmp(uuid, AVRCP_TARGET_UUID)) {
+ if (device->control)
+ return device;
+
+ device->control = control_init(device);
+
+ if (!device->control)
+ return NULL;
+ } else
+ return NULL;
+
+ path = device->path;
+
+ if (created) {
+ g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DeviceCreated",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ resolve_services(NULL, device, NULL, NULL);
+ }
+
+ if (headset)
+ g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "HeadsetCreated",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ if (headset && !default_hs) {
+ default_hs = device;
+ g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultHeadsetChanged",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ }
+
+ if (!default_dev) {
+ default_dev = device;
+ g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultDeviceChanged",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ }
+
+ return device;
+}
+
+gboolean manager_create_device(bdaddr_t *bda, create_dev_cb_t cb,
+ void *user_data)
+{
+ struct audio_device *dev;
+
+ dev = create_device(bda);
+ if (!dev)
+ return FALSE;
+
+ resolve_services(NULL, dev, cb, user_data);
+
+ return TRUE;
+}
+
+static DBusMessage *am_create_device(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ const char *address, *path;
+ bdaddr_t bda;
+ struct audio_device *device;
+ DBusMessage *reply;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ str2ba(address, &bda);
+
+ device = manager_find_device(&bda, NULL, FALSE);
+ if (!device) {
+ device = create_device(&bda);
+ return resolve_services(msg, device, NULL, NULL);
+ }
+
+ path = device->path;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *am_list_devices(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessageIter iter, array_iter;
+ DBusMessage *reply;
+ DBusError derr;
+ GSList *l;
+ gboolean hs_only = FALSE;
+
+ dbus_error_init(&derr);
+
+ if (dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+ "ListHeadsets"))
+ hs_only = TRUE;
+ else
+ hs_only = FALSE;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ for (l = devices; l != NULL; l = l->next) {
+ struct audio_device *device = l->data;
+
+ if (hs_only && !device->headset)
+ continue;
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &device->path);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static gint device_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct audio_device *device = a;
+ const char *path = b;
+
+ return strcmp(device->path, path);
+}
+
+static DBusMessage *am_remove_device(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessage *reply;
+ GSList *match;
+ const char *path;
+ struct audio_device *device;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ match = g_slist_find_custom(devices, path, device_path_cmp);
+ if (!match)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists",
+ "Device does not exists");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ device = match->data;
+ device_remove_stored(device);
+ remove_device(device);
+
+ /* Fallback to a valid default */
+ if (default_dev == NULL) {
+ const char *param;
+ GSList *l;
+
+ default_dev = manager_find_device(BDADDR_ANY, NULL, TRUE);
+
+ if (!default_dev && devices) {
+ l = devices;
+ default_dev = (g_slist_last(l))->data;
+ }
+
+ param = default_dev ? default_dev->path : "";
+
+ g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultHeadsetChanged",
+ DBUS_TYPE_STRING, &param,
+ DBUS_TYPE_INVALID);
+
+ g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultDeviceChanged",
+ DBUS_TYPE_STRING, &param,
+ DBUS_TYPE_INVALID);
+
+ if (default_dev)
+ device_store(default_dev, TRUE);
+ }
+
+ g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "HeadsetRemoved",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DeviceRemoved",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *am_find_by_addr(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ const char *address;
+ DBusMessage *reply;
+ struct audio_device *device;
+ bdaddr_t bda;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ str2ba(address, &bda);
+ device = manager_find_device(&bda, NULL, FALSE);
+
+ if (!device)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists",
+ "Device does not exists");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *am_default_device(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessage *reply;
+
+ if (!default_dev)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists",
+ "Device does not exists");
+
+ if (default_dev->headset == NULL &&
+ dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+ "DefaultHeadset"))
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists",
+ "Device does not exists");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_dev->path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *am_change_default_device(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessage *reply;
+ GSList *match;
+ const char *path;
+ struct audio_device *device;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ match = g_slist_find_custom(devices, path, device_path_cmp);
+ if (!match)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists",
+ "Device does not exists");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ device = match->data;
+
+ if (!dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+ "ChangeDefaultHeadset"))
+ g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultDeviceChanged",
+ DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+ else if (device->headset)
+ g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultHeadsetChanged",
+ DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+ else
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists",
+ "Device does not exists");
+
+ default_dev = device;
+ device_store(device, TRUE);
+
+ return reply;
+}
+
+static GDBusMethodTable manager_methods[] = {
+ { "CreateDevice", "s", "s", am_create_device,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "RemoveDevice", "s", "", am_remove_device },
+ { "ListDevices", "", "as", am_list_devices },
+ { "DefaultDevice", "", "s", am_default_device },
+ { "ChangeDefaultDevice", "s", "", am_change_default_device },
+ { "CreateHeadset", "s", "s", am_create_device,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "RemoveHeadset", "s", "", am_remove_device },
+ { "ListHeadsets", "", "as", am_list_devices },
+ { "FindDeviceByAddress", "s", "s", am_find_by_addr },
+ { "DefaultHeadset", "", "s", am_default_device },
+ { "ChangeDefaultHeadset", "s", "", am_change_default_device },
+ { }
+};
+
+static GDBusSignalTable manager_signals[] = {
+ { "DeviceCreated", "s" },
+ { "DeviceRemoved", "s" },
+ { "HeadsetCreated", "s" },
+ { "HeadsetRemoved", "s" },
+ { "DefaultDeviceChanged", "s" },
+ { "DefaultHeadsetChanged", "s" },
+ { }
+};
+
+static void parse_stored_devices(char *key, char *value, void *data)
+{
+ bdaddr_t *src = data;
+ struct audio_device *device;
+ bdaddr_t dst;
+
+ if (!key || !value || strcmp(key, "default") == 0)
+ return;
+
+ str2ba(key, &dst);
+ device = manager_find_device(&dst, NULL, FALSE);
+
+ if (device)
+ return;
+
+ info("Loading device %s (%s)", key, value);
+
+ device = create_device(&dst);
+ if (!device)
+ return;
+
+ /* Change storage to source adapter */
+ bacpy(&device->store, src);
+
+ if (enabled.headset && strstr(value, "headset"))
+ device->headset = headset_init(device, NULL, 0);
+ if (enabled.sink && strstr(value, "sink"))
+ device->sink = sink_init(device);
+ if (enabled.control && strstr(value, "control"))
+ device->control = control_init(device);
+ add_device(device, FALSE);
+}
+
+static void register_devices_stored(const char *adapter)
+{
+ char filename[PATH_MAX + 1];
+ struct stat st;
+ struct audio_device *device;
+ bdaddr_t default_src;
+ bdaddr_t dst;
+ bdaddr_t src;
+ char *addr;
+ int dev_id;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter, "audio");
+
+ str2ba(adapter, &src);
+
+ if (stat(filename, &st) < 0)
+ return;
+
+ if (!(st.st_mode & __S_IFREG))
+ return;
+
+ textfile_foreach(filename, parse_stored_devices, &src);
+
+ bacpy(&default_src, BDADDR_ANY);
+ dev_id = hci_get_route(&default_src);
+ if (dev_id < 0 || hci_devba(dev_id, &default_src) < 0)
+ return;
+
+ if (bacmp(&default_src, &src) != 0)
+ return;
+
+ addr = textfile_get(filename, "default");
+ if (!addr)
+ return;
+
+ str2ba(addr, &dst);
+ device = manager_find_device(&dst, NULL, FALSE);
+
+ if (device) {
+ info("Setting %s as default device", addr);
+ default_dev = device;
+ }
+
+ free(addr);
+}
+
+static void register_stored(void)
+{
+ char dirname[PATH_MAX + 1];
+ struct dirent *de;
+ DIR *dir;
+
+ snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
+
+ dir = opendir(dirname);
+ if (!dir)
+ return;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (!isdigit(de->d_name[0]))
+ continue;
+
+ /* Device objects */
+ register_devices_stored(de->d_name);
+ }
+
+ closedir(dir);
+}
+
+static void manager_unregister(void *data)
+{
+ info("Unregistered manager path");
+
+ if (devices) {
+ g_slist_foreach(devices, (GFunc) remove_device, NULL);
+ g_slist_free(devices);
+ devices = NULL;
+ }
+}
+
+static sdp_record_t *hsp_ag_record(uint8_t ch)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_list_t *aproto, *proto[2];
+ sdp_data_t *channel;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &ch);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Headset Audio Gateway", 0, 0);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static sdp_record_t *hsp_hs_record(uint8_t ch)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_list_t *aproto, *proto[2];
+ sdp_data_t *channel;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &ch);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Headset", 0, 0);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static sdp_record_t *hfp_ag_record(uint8_t ch, uint32_t feat)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *channel, *features;
+ uint8_t netid = 0x01;
+ uint16_t sdpfeat;
+ sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+ profile.version = 0x0105;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &ch);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ sdpfeat = (uint16_t) feat & 0xF;
+ features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
+
+ sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
+static void auth_cb(DBusError *derr, void *user_data)
+{
+ struct audio_device *device = user_data;
+ const char *uuid;
+
+ if (get_hfp_active(device))
+ uuid = HFP_AG_UUID;
+ else
+ uuid = HSP_AG_UUID;
+
+ if (derr && dbus_error_is_set(derr)) {
+ error("Access denied: %s", derr->message);
+ if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {
+ debug("Canceling authorization request");
+ service_cancel_auth(&device->src, &device->dst);
+ }
+
+ headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+ } else {
+ char hs_address[18];
+
+ headset_set_authorized(device);
+
+ ba2str(&device->dst, hs_address);
+
+ debug("Accepted headset connection from %s for %s",
+ hs_address, device->path);
+ headset_set_state(device, HEADSET_STATE_CONNECTED);
+ }
+}
+
+static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer data)
+{
+ const char *uuid;
+ struct audio_device *device;
+ gboolean hfp_active;
+
+ if (err < 0) {
+ error("accept: %s (%d)", strerror(-err), -err);
+ return;
+ }
+
+ if (chan == hsp_ag_server) {
+ hfp_active = FALSE;
+ uuid = HSP_AG_UUID;
+ } else {
+ hfp_active = TRUE;
+ uuid = HFP_AG_UUID;
+ }
+
+ device = manager_device_connected(dst, uuid);
+ if (!device)
+ goto drop;
+
+ if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
+ debug("Refusing new connection since one already exists");
+ goto drop;
+ }
+
+ set_hfp_active(device, hfp_active);
+
+ if (headset_connect_rfcomm(device, chan) < 0) {
+ error("Allocating new GIOChannel failed!");
+ goto drop;
+ }
+
+ err = service_req_auth(&device->src, &device->dst, uuid, auth_cb,
+ device);
+ if (err < 0) {
+ debug("Authorization denied: %s", strerror(-err));
+ headset_close_rfcomm(device);
+ return;
+ }
+
+ headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);
+
+ return;
+
+drop:
+ g_io_channel_close(chan);
+ g_io_channel_unref(chan);
+ return;
+}
+
+static void hs_io_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, void *data)
+{
+ /*Stub*/
+ return;
+}
+
+static int headset_server_init(DBusConnection *conn, GKeyFile *config)
+{
+ uint8_t chan = DEFAULT_HS_AG_CHANNEL;
+ sdp_record_t *record;
+ gboolean hfp = TRUE, master = TRUE;
+ GError *err = NULL;
+ uint32_t features, flags;
+
+ if (!enabled.headset)
+ return 0;
+
+ if (config) {
+ gboolean tmp;
+
+ tmp = g_key_file_get_boolean(config, "General", "Master",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else
+ master = tmp;
+
+ tmp = g_key_file_get_boolean(config, "Headset", "HFP",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else
+ hfp = tmp;
+ }
+
+ flags = RFCOMM_LM_SECURE;
+
+ if (master)
+ flags |= RFCOMM_LM_MASTER;
+
+ hsp_ag_server = bt_rfcomm_listen(BDADDR_ANY, chan, flags, ag_io_cb,
+ NULL);
+ if (!hsp_ag_server)
+ return -1;
+
+ record = hsp_ag_record(chan);
+ if (!record) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ error("Unable to register HS AG service record");
+ sdp_record_free(record);
+ g_io_channel_unref(hsp_ag_server);
+ hsp_ag_server = NULL;
+ return -1;
+ }
+ hsp_ag_record_id = record->handle;
+
+ features = headset_config_init(config);
+
+ if (!hfp)
+ return 0;
+
+ chan = DEFAULT_HF_AG_CHANNEL;
+
+ hfp_ag_server = bt_rfcomm_listen(BDADDR_ANY, chan, flags, ag_io_cb,
+ NULL);
+ if (!hfp_ag_server)
+ return -1;
+
+ record = hfp_ag_record(chan, features);
+ if (!record) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ error("Unable to register HF AG service record");
+ sdp_record_free(record);
+ g_io_channel_unref(hfp_ag_server);
+ hfp_ag_server = NULL;
+ return -1;
+ }
+ hfp_ag_record_id = record->handle;
+
+ return 0;
+}
+
+static int gateway_server_init(DBusConnection *conn, GKeyFile *config)
+{
+ uint8_t chan = DEFAULT_HSP_HS_CHANNEL;
+ sdp_record_t *record;
+ gboolean master = TRUE;
+ GError *err = NULL;
+ uint32_t flags;
+
+ if (!enabled.gateway)
+ return 0;
+
+ if (config) {
+ gboolean tmp;
+
+ tmp = g_key_file_get_boolean(config, "General", "Master",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else
+ master = tmp;
+ }
+
+ flags = RFCOMM_LM_SECURE;
+
+ if (master)
+ flags |= RFCOMM_LM_MASTER;
+
+ hsp_hs_server = bt_rfcomm_listen(BDADDR_ANY, chan, flags, hs_io_cb,
+ NULL);
+ if (!hsp_hs_server)
+ return -1;
+
+ record = hsp_hs_record(chan);
+ if (!record) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ error("Unable to register HSP HS service record");
+ sdp_record_free(record);
+ g_io_channel_unref(hsp_hs_server);
+ hsp_hs_server = NULL;
+ return -1;
+ }
+
+ hsp_hs_record_id = record->handle;
+
+ return 0;
+}
+
+static void server_exit(void)
+{
+ if (hsp_ag_record_id) {
+ remove_record_from_server(hsp_ag_record_id);
+ hsp_ag_record_id = 0;
+ }
+
+ if (hsp_ag_server) {
+ g_io_channel_unref(hsp_ag_server);
+ hsp_ag_server = NULL;
+ }
+
+ if (hsp_hs_record_id) {
+ remove_record_from_server(hsp_hs_record_id);
+ hsp_hs_record_id = 0;
+ }
+
+ if (hsp_hs_server) {
+ g_io_channel_unref(hsp_hs_server);
+ hsp_hs_server = NULL;
+ }
+
+ if (hfp_ag_record_id) {
+ remove_record_from_server(hfp_ag_record_id);
+ hfp_ag_record_id = 0;
+ }
+
+ if (hfp_ag_server) {
+ g_io_channel_unref(hfp_ag_server);
+ hfp_ag_server = NULL;
+ }
+}
+
+int audio_manager_init(DBusConnection *conn, GKeyFile *config)
+{
+ char **list;
+ int i;
+
+ connection = dbus_connection_ref(conn);
+
+ if (!config)
+ goto proceed;
+
+ list = g_key_file_get_string_list(config, "General", "Enable",
+ NULL, NULL);
+ for (i = 0; list && list[i] != NULL; i++) {
+ if (g_str_equal(list[i], "Headset"))
+ enabled.headset = TRUE;
+ else if (g_str_equal(list[i], "Gateway"))
+ enabled.gateway = TRUE;
+ else if (g_str_equal(list[i], "Sink"))
+ enabled.sink = TRUE;
+ else if (g_str_equal(list[i], "Source"))
+ enabled.source = TRUE;
+ else if (g_str_equal(list[i], "Control"))
+ enabled.control = TRUE;
+ }
+ g_strfreev(list);
+
+ list = g_key_file_get_string_list(config, "General", "Disable",
+ NULL, NULL);
+ for (i = 0; list && list[i] != NULL; i++) {
+ if (g_str_equal(list[i], "Headset"))
+ enabled.headset = FALSE;
+ else if (g_str_equal(list[i], "Gateway"))
+ enabled.gateway = FALSE;
+ else if (g_str_equal(list[i], "Sink"))
+ enabled.sink = FALSE;
+ else if (g_str_equal(list[i], "Source"))
+ enabled.source = FALSE;
+ else if (g_str_equal(list[i], "Control"))
+ enabled.control = FALSE;
+ }
+ g_strfreev(list);
+
+proceed:
+ if (enabled.headset) {
+ if (headset_server_init(conn, config) < 0)
+ goto failed;
+ }
+
+ if (enabled.gateway) {
+ if (gateway_server_init(conn, config) < 0)
+ goto failed;
+ }
+
+ if (enabled.source || enabled.sink) {
+ if (a2dp_init(conn, config) < 0)
+ goto failed;
+ }
+
+ if (enabled.control && avrcp_init(conn, config) < 0)
+ goto failed;
+
+ if (!g_dbus_register_interface(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ manager_methods, manager_signals,
+ NULL, NULL, manager_unregister)) {
+ error("Failed to register %s interface to %s",
+ AUDIO_MANAGER_INTERFACE, AUDIO_MANAGER_PATH);
+ goto failed;
+ }
+
+ info("Registered manager path:%s", AUDIO_MANAGER_PATH);
+
+ register_stored();
+
+ return 0;
+failed:
+ audio_manager_exit();
+ return -1;
+}
+
+void audio_manager_exit(void)
+{
+ server_exit();
+
+ g_dbus_unregister_interface(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE);
+
+ dbus_connection_unref(connection);
+
+ connection = NULL;
+}
+
+struct audio_device *manager_default_device(void)
+{
+ return default_dev;
+}
+
+struct audio_device *manager_get_connected_device(void)
+{
+ GSList *l;
+
+ for (l = devices; l != NULL; l = g_slist_next(l)) {
+ struct audio_device *device = l->data;
+
+ if ((device->sink || device->source) &&
+ avdtp_is_connected(&device->src, &device->dst))
+ return device;
+
+ if (device->headset && headset_is_active(device))
+ return device;
+ }
+
+ return NULL;
+}
+
+struct audio_device *manager_find_device(const bdaddr_t *bda, const char *interface,
+ gboolean connected)
+{
+ GSList *l;
+
+ if (!bacmp(bda, BDADDR_ANY) && !interface && !connected)
+ return default_dev;
+
+ for (l = devices; l != NULL; l = l->next) {
+ struct audio_device *dev = l->data;
+
+ if (bacmp(bda, BDADDR_ANY) && bacmp(&dev->dst, bda))
+ continue;
+
+ if (interface && !strcmp(AUDIO_HEADSET_INTERFACE, interface)
+ && !dev->headset)
+ continue;
+
+ if (interface && !strcmp(AUDIO_SINK_INTERFACE, interface)
+ && !dev->sink)
+ continue;
+
+ if (interface && !strcmp(AUDIO_SOURCE_INTERFACE, interface)
+ && !dev->source)
+ continue;
+
+ if (interface && !strcmp(AUDIO_CONTROL_INTERFACE, interface)
+ && !dev->control)
+ continue;
+
+ if (connected && !device_is_connected(dev, interface))
+ continue;
+
+ return dev;
+ }
+
+ return NULL;
+}
diff --git a/utils/audio/manager.h b/utils/audio/manager.h
new file mode 100644
index 00000000..8f7f6be3
--- /dev/null
+++ b/utils/audio/manager.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define MAX_PATH_LENGTH 64 /* D-Bus path */
+#define AUDIO_MANAGER_PATH "/org/bluez/audio"
+#define AUDIO_MANAGER_INTERFACE "org.bluez.audio.Manager"
+
+struct enabled_interfaces {
+ gboolean headset;
+ gboolean gateway;
+ gboolean sink;
+ gboolean source;
+ gboolean control;
+};
+
+typedef void (*create_dev_cb_t) (struct audio_device *dev, void *user_data);
+
+int audio_manager_init(DBusConnection *conn, GKeyFile *config);
+void audio_manager_exit(void);
+
+gboolean server_is_enabled(uint16_t svc);
+
+struct audio_device *manager_find_device(const bdaddr_t *bda, const char *interface,
+ gboolean connected);
+
+struct audio_device *manager_device_connected(const bdaddr_t *bda, const char *uuid);
+
+gboolean manager_create_device(bdaddr_t *bda, create_dev_cb_t cb,
+ void *user_data);
diff --git a/utils/audio/pcm_bluetooth.c b/utils/audio/pcm_bluetooth.c
new file mode 100644
index 00000000..0dec0a12
--- /dev/null
+++ b/utils/audio/pcm_bluetooth.c
@@ -0,0 +1,1665 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <signal.h>
+#include <limits.h>
+
+#include <netinet/in.h>
+
+#include <alsa/asoundlib.h>
+#include <alsa/pcm_external.h>
+
+#include "ipc.h"
+#include "sbc.h"
+#include "rtp.h"
+
+//#define ENABLE_DEBUG
+
+#define UINT_SECS_MAX (UINT_MAX / 1000000 - 1)
+
+#define MIN_PERIOD_TIME 1
+
+#define BUFFER_SIZE 2048
+
+#ifdef ENABLE_DEBUG
+#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#else
+#define DBG(fmt, arg...)
+#endif
+
+#ifndef SOL_SCO
+#define SOL_SCO 17
+#endif
+
+#ifndef SCO_TXBUFS
+#define SCO_TXBUFS 0x03
+#endif
+
+#ifndef SCO_RXBUFS
+#define SCO_RXBUFS 0x04
+#endif
+
+#ifndef MIN
+# define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+#ifndef MAX
+# define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#define MAX_BITPOOL 64
+#define MIN_BITPOOL 2
+
+/* adapted from glibc sys/time.h timersub() macro */
+#define priv_timespecsub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
+ if ((result)->tv_nsec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_nsec += 1000000000; \
+ } \
+ } while (0)
+
+struct bluetooth_a2dp {
+ sbc_capabilities_t sbc_capabilities;
+ sbc_t sbc; /* Codec data */
+ int sbc_initialized; /* Keep track if the encoder is initialized */
+ int codesize; /* SBC codesize */
+ int samples; /* Number of encoded samples */
+ uint8_t buffer[BUFFER_SIZE]; /* Codec transfer buffer */
+ int count; /* Codec transfer buffer counter */
+
+ int nsamples; /* Cumulative number of codec samples */
+ uint16_t seq_num; /* Cumulative packet sequence */
+ int frame_count; /* Current frames in buffer*/
+};
+
+struct bluetooth_alsa_config {
+ char device[18]; /* Address of the remote Device */
+ int has_device;
+ uint8_t transport; /* Requested transport */
+ int has_transport;
+ uint16_t rate;
+ int has_rate;
+ uint8_t channel_mode; /* A2DP only */
+ int has_channel_mode;
+ uint8_t allocation_method; /* A2DP only */
+ int has_allocation_method;
+ uint8_t subbands; /* A2DP only */
+ int has_subbands;
+ uint8_t block_length; /* A2DP only */
+ int has_block_length;
+ uint8_t bitpool; /* A2DP only */
+ int has_bitpool;
+ int autoconnect;
+};
+
+struct bluetooth_data {
+ snd_pcm_ioplug_t io;
+ struct bluetooth_alsa_config alsa_config; /* ALSA resource file parameters */
+ volatile snd_pcm_sframes_t hw_ptr;
+ int transport; /* chosen transport SCO or AD2P */
+ int link_mtu; /* MTU for selected transport channel */
+ volatile struct pollfd stream; /* Audio stream filedescriptor */
+ struct pollfd server; /* Audio daemon filedescriptor */
+ uint8_t buffer[BUFFER_SIZE]; /* Encoded transfer buffer */
+ int count; /* Transfer buffer counter */
+ struct bluetooth_a2dp a2dp; /* A2DP data */
+
+ pthread_t hw_thread; /* Makes virtual hw pointer move */
+ int pipefd[2]; /* Inter thread communication */
+ int stopped;
+ sig_atomic_t reset; /* Request XRUN handling */
+};
+
+static int audioservice_send(int sk, const bt_audio_msg_header_t *msg);
+static int audioservice_expect(int sk, bt_audio_msg_header_t *outmsg,
+ int expected_type);
+
+static int bluetooth_start(snd_pcm_ioplug_t *io)
+{
+ DBG("bluetooth_start %p", io);
+
+ return 0;
+}
+
+static int bluetooth_stop(snd_pcm_ioplug_t *io)
+{
+ DBG("bluetooth_stop %p", io);
+
+ return 0;
+}
+
+static void *playback_hw_thread(void *param)
+{
+ struct bluetooth_data *data = param;
+ unsigned int prev_periods;
+ double period_time;
+ struct timespec start;
+ struct pollfd fds[2];
+ int poll_timeout;
+
+ data->server.events = POLLIN;
+ /* note: only errors for data->stream.events */
+
+ fds[0] = data->server;
+ fds[1] = data->stream;
+
+ prev_periods = 0;
+ period_time = 1000000.0 * data->io.period_size / data->io.rate;
+ if (period_time > (int) (MIN_PERIOD_TIME * 1000))
+ poll_timeout = (int) (period_time / 1000.0f);
+ else
+ poll_timeout = MIN_PERIOD_TIME;
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ while (1) {
+ unsigned int dtime, periods;
+ struct timespec cur, delta;
+ int ret;
+
+ if (data->stopped)
+ goto iter_sleep;
+
+ if (data->reset) {
+ DBG("Handle XRUN in hw-thread.");
+ data->reset = 0;
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ prev_periods = 0;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &cur);
+
+ priv_timespecsub(&cur, &start, &delta);
+
+ dtime = delta.tv_sec * 1000000 + delta.tv_nsec / 1000;
+ periods = 1.0 * dtime / period_time;
+
+ if (periods > prev_periods) {
+ char c = 'w';
+ int frags = periods - prev_periods, n;
+
+ data->hw_ptr += frags * data->io.period_size;
+ data->hw_ptr %= data->io.buffer_size;
+
+ for (n = 0; n < frags; n++) {
+ /* Notify user that hardware pointer
+ * has moved * */
+ if (write(data->pipefd[1], &c, 1) < 0)
+ pthread_testcancel();
+ }
+
+ /* Reset point of reference to avoid too big values
+ * that wont fit an unsigned int */
+ if (delta.tv_sec < UINT_SECS_MAX)
+ prev_periods = periods;
+ else {
+ prev_periods = 0;
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ }
+ }
+
+iter_sleep:
+ /* sleep up to one period interval */
+ ret = poll(fds, 2, poll_timeout);
+
+ if (ret < 0) {
+ SNDERR("poll error: %s (%d)", strerror(errno), errno);
+ if (errno != EINTR)
+ break;
+ } else if (ret > 0) {
+ ret = (fds[0].revents) ? 0 : 1;
+ SNDERR("poll fd %d revents %d", ret, fds[ret].revents);
+ if (fds[ret].revents & (POLLERR | POLLHUP | POLLNVAL))
+ break;
+ }
+
+ /* Offer opportunity to be canceled by main thread */
+ pthread_testcancel();
+ }
+
+ data->hw_thread = 0;
+ pthread_exit(NULL);
+}
+
+static int bluetooth_playback_start(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+ int err;
+
+ DBG("%p", io);
+
+ data->stopped = 0;
+
+ if (data->hw_thread)
+ return 0;
+
+ err = pthread_create(&data->hw_thread, 0, playback_hw_thread, data);
+
+ return -err;
+}
+
+static int bluetooth_playback_stop(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+
+ DBG("%p", io);
+
+ data->stopped = 1;
+
+ return 0;
+}
+
+static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+
+ return data->hw_ptr;
+}
+
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+ struct bluetooth_a2dp *a2dp = &data->a2dp;
+
+ if (data->server.fd >= 0)
+ bt_audio_service_close(data->server.fd);
+
+ if (data->stream.fd >= 0)
+ close(data->stream.fd);
+
+ if (data->hw_thread) {
+ pthread_cancel(data->hw_thread);
+ pthread_join(data->hw_thread, 0);
+ }
+
+ if (a2dp->sbc_initialized)
+ sbc_finish(&a2dp->sbc);
+
+ if (data->pipefd[0] > 0)
+ close(data->pipefd[0]);
+
+ if (data->pipefd[1] > 0)
+ close(data->pipefd[1]);
+
+ free(data);
+}
+
+static int bluetooth_close(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+
+ DBG("%p", io);
+
+ bluetooth_exit(data);
+
+ return 0;
+}
+
+static int bluetooth_prepare(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+ char c = 'w';
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_streamstart_req *start_req = (void*) buf;
+ bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf;
+ struct bt_streamfd_ind *streamfd_ind = (void*) buf;
+ uint32_t period_count = io->buffer_size / io->period_size;
+ int opt_name, err;
+ struct timeval t = { 0, period_count };
+
+ DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
+ io->period_size, io->buffer_size);
+
+ data->reset = 0;
+
+ /* As we're gonna receive messages on the server socket, we have to stop the
+ hw thread that is polling on it, if any */
+ if (data->hw_thread) {
+ pthread_cancel(data->hw_thread);
+ pthread_join(data->hw_thread, 0);
+ data->hw_thread = 0;
+ }
+
+ if (io->stream == SND_PCM_STREAM_PLAYBACK)
+ /* If not null for playback, xmms doesn't display time
+ * correctly */
+ data->hw_ptr = 0;
+ else
+ /* ALSA library is really picky on the fact hw_ptr is not null.
+ * If it is, capture won't start */
+ data->hw_ptr = io->period_size;
+
+ /* send start */
+ memset(start_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ start_req->h.msg_type = BT_STREAMSTART_REQ;
+
+ err = audioservice_send(data->server.fd, &start_req->h);
+ if (err < 0)
+ return err;
+
+ err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h,
+ BT_STREAMSTART_RSP);
+ if (err < 0)
+ return err;
+
+ if (rsp_hdr->posix_errno != 0) {
+ SNDERR("BT_START failed : %s(%d)",
+ strerror(rsp_hdr->posix_errno),
+ rsp_hdr->posix_errno);
+ return -rsp_hdr->posix_errno;
+ }
+
+ err = audioservice_expect(data->server.fd, &streamfd_ind->h,
+ BT_STREAMFD_IND);
+ if (err < 0)
+ return err;
+
+ if (data->stream.fd >= 0)
+ close(data->stream.fd);
+
+ data->stream.fd = bt_audio_service_get_data_fd(data->server.fd);
+ if (data->stream.fd < 0) {
+ return -errno;
+ }
+
+ if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
+ opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+ SO_SNDTIMEO : SO_RCVTIMEO;
+
+ if (setsockopt(data->stream.fd, SOL_SOCKET, opt_name, &t,
+ sizeof(t)) < 0)
+ return -errno;
+ } else {
+ opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+ SCO_TXBUFS : SCO_RXBUFS;
+
+ if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,
+ sizeof(period_count)) == 0)
+ return 0;
+
+ opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+ SO_SNDBUF : SO_RCVBUF;
+
+ if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,
+ sizeof(period_count)) == 0)
+ return 0;
+
+ /* FIXME : handle error codes */
+ }
+
+ /* wake up any client polling at us */
+ err = write(data->pipefd[1], &c, 1);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int bluetooth_hsp_hw_params(snd_pcm_ioplug_t *io,
+ snd_pcm_hw_params_t *params)
+{
+ struct bluetooth_data *data = io->private_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf;
+ struct bt_setconfiguration_req *setconf_req = (void*) buf;
+ struct bt_setconfiguration_rsp *setconf_rsp = (void*) buf;
+ int err;
+
+ DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
+ io->period_size, io->buffer_size);
+
+ memset(setconf_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ setconf_req->h.msg_type = BT_SETCONFIGURATION_REQ;
+ strncpy(setconf_req->device, data->alsa_config.device, 18);
+ setconf_req->transport = BT_CAPABILITIES_TRANSPORT_SCO;
+ setconf_req->access_mode = (io->stream == SND_PCM_STREAM_PLAYBACK ?
+ BT_CAPABILITIES_ACCESS_MODE_WRITE :
+ BT_CAPABILITIES_ACCESS_MODE_READ);
+
+ err = audioservice_send(data->server.fd, &setconf_req->h);
+ if (err < 0)
+ return err;
+
+ err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h,
+ BT_SETCONFIGURATION_RSP);
+ if (err < 0)
+ return err;
+
+ if (rsp_hdr->posix_errno != 0) {
+ SNDERR("BT_SETCONFIGURATION failed : %s(%d)",
+ strerror(rsp_hdr->posix_errno),
+ rsp_hdr->posix_errno);
+ return -rsp_hdr->posix_errno;
+ }
+
+ data->transport = setconf_rsp->transport;
+ data->link_mtu = setconf_rsp->link_mtu;
+
+ return 0;
+}
+
+static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
+{
+ switch (freq) {
+ case BT_SBC_SAMPLING_FREQ_16000:
+ case BT_SBC_SAMPLING_FREQ_32000:
+ return 53;
+ case BT_SBC_SAMPLING_FREQ_44100:
+ switch (mode) {
+ case BT_A2DP_CHANNEL_MODE_MONO:
+ case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+ return 31;
+ case BT_A2DP_CHANNEL_MODE_STEREO:
+ case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
+ return 53;
+ default:
+ DBG("Invalid channel mode %u", mode);
+ return 53;
+ }
+ case BT_SBC_SAMPLING_FREQ_48000:
+ switch (mode) {
+ case BT_A2DP_CHANNEL_MODE_MONO:
+ case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+ return 29;
+ case BT_A2DP_CHANNEL_MODE_STEREO:
+ case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
+ return 51;
+ default:
+ DBG("Invalid channel mode %u", mode);
+ return 51;
+ }
+ default:
+ DBG("Invalid sampling freq %u", freq);
+ return 53;
+ }
+}
+
+static int bluetooth_a2dp_init(struct bluetooth_data *data,
+ snd_pcm_hw_params_t *params)
+{
+ struct bluetooth_alsa_config *cfg = &data->alsa_config;
+ sbc_capabilities_t *cap = &data->a2dp.sbc_capabilities;
+ unsigned int max_bitpool, min_bitpool, rate, channels;
+ int dir;
+
+ snd_pcm_hw_params_get_rate(params, &rate, &dir);
+ snd_pcm_hw_params_get_channels(params, &channels);
+
+ switch (rate) {
+ case 48000:
+ cap->frequency = BT_SBC_SAMPLING_FREQ_48000;
+ break;
+ case 44100:
+ cap->frequency = BT_SBC_SAMPLING_FREQ_44100;
+ break;
+ case 32000:
+ cap->frequency = BT_SBC_SAMPLING_FREQ_32000;
+ break;
+ case 16000:
+ cap->frequency = BT_SBC_SAMPLING_FREQ_16000;
+ break;
+ default:
+ DBG("Rate %d not supported", rate);
+ return -1;
+ }
+
+ if (cfg->has_channel_mode)
+ cap->channel_mode = cfg->channel_mode;
+ else if (channels == 2) {
+ if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+ else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
+ else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
+ } else {
+ if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
+ }
+
+ if (!cap->channel_mode) {
+ DBG("No supported channel modes");
+ return -1;
+ }
+
+ if (cfg->has_block_length)
+ cap->block_length = cfg->block_length;
+ else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_16;
+ else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_12;
+ else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_8;
+ else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_4;
+ else {
+ DBG("No supported block lengths");
+ return -1;
+ }
+
+ if (cfg->has_subbands)
+ cap->subbands = cfg->subbands;
+ if (cap->subbands & BT_A2DP_SUBBANDS_8)
+ cap->subbands = BT_A2DP_SUBBANDS_8;
+ else if (cap->subbands & BT_A2DP_SUBBANDS_4)
+ cap->subbands = BT_A2DP_SUBBANDS_4;
+ else {
+ DBG("No supported subbands");
+ return -1;
+ }
+
+ if (cfg->has_allocation_method)
+ cap->allocation_method = cfg->allocation_method;
+ if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS)
+ cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
+ else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR)
+ cap->allocation_method = BT_A2DP_ALLOCATION_SNR;
+
+ if (cfg->has_bitpool)
+ min_bitpool = max_bitpool = cfg->bitpool;
+ else {
+ min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool);
+ max_bitpool = MIN(default_bitpool(cap->frequency,
+ cap->channel_mode),
+ cap->max_bitpool);
+ }
+
+ cap->min_bitpool = min_bitpool;
+ cap->max_bitpool = max_bitpool;
+
+ return 0;
+}
+
+static void bluetooth_a2dp_setup(struct bluetooth_a2dp *a2dp)
+{
+ sbc_capabilities_t active_capabilities = a2dp->sbc_capabilities;
+
+ if (a2dp->sbc_initialized)
+ sbc_reinit(&a2dp->sbc, 0);
+ else
+ sbc_init(&a2dp->sbc, 0);
+ a2dp->sbc_initialized = 1;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000)
+ a2dp->sbc.frequency = SBC_FREQ_16000;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_32000)
+ a2dp->sbc.frequency = SBC_FREQ_32000;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_44100)
+ a2dp->sbc.frequency = SBC_FREQ_44100;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_48000)
+ a2dp->sbc.frequency = SBC_FREQ_48000;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
+ a2dp->sbc.mode = SBC_MODE_MONO;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
+ a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
+ a2dp->sbc.mode = SBC_MODE_STEREO;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
+ a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
+
+ a2dp->sbc.allocation = active_capabilities.allocation_method
+ == BT_A2DP_ALLOCATION_SNR ? SBC_AM_SNR
+ : SBC_AM_LOUDNESS;
+
+ switch (active_capabilities.subbands) {
+ case BT_A2DP_SUBBANDS_4:
+ a2dp->sbc.subbands = SBC_SB_4;
+ break;
+ case BT_A2DP_SUBBANDS_8:
+ a2dp->sbc.subbands = SBC_SB_8;
+ break;
+ }
+
+ switch (active_capabilities.block_length) {
+ case BT_A2DP_BLOCK_LENGTH_4:
+ a2dp->sbc.blocks = SBC_BLK_4;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_8:
+ a2dp->sbc.blocks = SBC_BLK_8;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_12:
+ a2dp->sbc.blocks = SBC_BLK_12;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_16:
+ a2dp->sbc.blocks = SBC_BLK_16;
+ break;
+ }
+
+ a2dp->sbc.bitpool = active_capabilities.max_bitpool;
+ a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
+ a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+}
+
+static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io,
+ snd_pcm_hw_params_t *params)
+{
+ struct bluetooth_data *data = io->private_data;
+ struct bluetooth_a2dp *a2dp = &data->a2dp;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf;
+ struct bt_setconfiguration_req *setconf_req = (void*) buf;
+ struct bt_setconfiguration_rsp *setconf_rsp = (void*) buf;
+ int err;
+
+ DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
+ io->period_size, io->buffer_size);
+
+ err = bluetooth_a2dp_init(data, params);
+ if (err < 0)
+ return err;
+
+ memset(setconf_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ setconf_req->h.msg_type = BT_SETCONFIGURATION_REQ;
+ strncpy(setconf_req->device, data->alsa_config.device, 18);
+ setconf_req->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
+ setconf_req->sbc_capabilities = a2dp->sbc_capabilities;
+ setconf_req->access_mode = (io->stream == SND_PCM_STREAM_PLAYBACK ?
+ BT_CAPABILITIES_ACCESS_MODE_WRITE :
+ BT_CAPABILITIES_ACCESS_MODE_READ);
+
+ err = audioservice_send(data->server.fd, &setconf_req->h);
+ if (err < 0)
+ return err;
+
+ err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h,
+ BT_SETCONFIGURATION_RSP);
+ if (err < 0)
+ return err;
+
+ if (rsp_hdr->posix_errno != 0) {
+ SNDERR("BT_SETCONFIGURATION failed : %s(%d)",
+ strerror(rsp_hdr->posix_errno),
+ rsp_hdr->posix_errno);
+ return -rsp_hdr->posix_errno;
+ }
+
+ data->transport = setconf_rsp->transport;
+ data->link_mtu = setconf_rsp->link_mtu;
+
+ /* Setup SBC encoder now we agree on parameters */
+ bluetooth_a2dp_setup(a2dp);
+
+ DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
+ a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks,
+ a2dp->sbc.bitpool);
+
+ return 0;
+}
+
+static int bluetooth_poll_descriptors(snd_pcm_ioplug_t *io,
+ struct pollfd *pfd, unsigned int space)
+{
+ struct bluetooth_data *data = io->private_data;
+
+ assert(io);
+
+ if (space < 1)
+ return 0;
+
+ pfd[0].fd = data->stream.fd;
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+
+ return 1;
+}
+
+static int bluetooth_poll_revents(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED,
+ struct pollfd *pfds, unsigned int nfds,
+ unsigned short *revents)
+{
+ assert(pfds && nfds == 1 && revents);
+
+ *revents = pfds[0].revents;
+
+ return 0;
+}
+
+static int bluetooth_playback_poll_descriptors_count(snd_pcm_ioplug_t *io)
+{
+ return 2;
+}
+
+static int bluetooth_playback_poll_descriptors(snd_pcm_ioplug_t *io,
+ struct pollfd *pfd, unsigned int space)
+{
+ struct bluetooth_data *data = io->private_data;
+
+ DBG("");
+
+ assert(data->pipefd[0] >= 0);
+
+ if (space < 2)
+ return 0;
+
+ pfd[0].fd = data->pipefd[0];
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+ pfd[1].fd = data->stream.fd;
+ pfd[1].events = POLLERR | POLLHUP | POLLNVAL;
+ pfd[1].revents = 0;
+
+ return 2;
+}
+
+static int bluetooth_playback_poll_revents(snd_pcm_ioplug_t *io,
+ struct pollfd *pfds, unsigned int nfds,
+ unsigned short *revents)
+{
+ static char buf[1];
+ int ret;
+
+ DBG("");
+
+ assert(pfds);
+ assert(nfds == 2);
+ assert(revents);
+ assert(pfds[0].fd >= 0);
+ assert(pfds[1].fd >= 0);
+
+ if (io->state != SND_PCM_STATE_PREPARED)
+ ret = read(pfds[0].fd, buf, 1);
+
+ if (pfds[1].revents & (POLLERR | POLLHUP | POLLNVAL))
+ io->state = SND_PCM_STATE_DISCONNECTED;
+
+ revents[0] = (pfds[0].revents & ~POLLIN) | POLLOUT;
+ revents[1] = (pfds[1].revents & ~POLLIN);
+
+ return 0;
+}
+
+
+static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
+{
+ struct bluetooth_data *data = io->private_data;
+ snd_pcm_uframes_t frames_to_write, ret;
+ unsigned char *buff;
+ int nrecv, frame_size = 0;
+
+ DBG("areas->step=%u areas->first=%u offset=%lu size=%lu io->nonblock=%u",
+ areas->step, areas->first, offset, size, io->nonblock);
+
+ frame_size = areas->step / 8;
+
+ if (data->count > 0)
+ goto proceed;
+
+ nrecv = recv(data->stream.fd, data->buffer, data->link_mtu,
+ MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0));
+
+ if (nrecv < 0) {
+ ret = (errno == EPIPE) ? -EIO : -errno;
+ goto done;
+ }
+
+ if (nrecv != data->link_mtu) {
+ ret = -EIO;
+ SNDERR(strerror(-ret));
+ goto done;
+ }
+
+ /* Increment hardware transmition pointer */
+ data->hw_ptr = (data->hw_ptr + data->link_mtu / frame_size) %
+ io->buffer_size;
+
+proceed:
+ buff = (unsigned char *) areas->addr +
+ (areas->first + areas->step * offset) / 8;
+
+ if ((data->count + size * frame_size) <= data->link_mtu)
+ frames_to_write = size;
+ else
+ frames_to_write = (data->link_mtu - data->count) / frame_size;
+
+ memcpy(buff, data->buffer + data->count, frame_size * frames_to_write);
+ data->count += (frame_size * frames_to_write);
+ data->count %= data->link_mtu;
+
+ /* Return written frames count */
+ ret = frames_to_write;
+
+done:
+ DBG("returning %lu", ret);
+ return ret;
+}
+
+static snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
+{
+ struct bluetooth_data *data = io->private_data;
+ snd_pcm_sframes_t ret = 0;
+ snd_pcm_uframes_t frames_to_read;
+ uint8_t *buff;
+ int rsend, frame_size;
+
+ DBG("areas->step=%u areas->first=%u offset=%lu, size=%lu io->nonblock=%u",
+ areas->step, areas->first, offset, size, io->nonblock);
+
+ if (io->hw_ptr > io->appl_ptr) {
+ ret = bluetooth_playback_stop(io);
+ if (ret == 0)
+ ret = -EPIPE;
+ goto done;
+ }
+
+ frame_size = areas->step / 8;
+ if ((data->count + size * frame_size) <= data->link_mtu)
+ frames_to_read = size;
+ else
+ frames_to_read = (data->link_mtu - data->count) / frame_size;
+
+ DBG("count=%d frames_to_read=%lu", data->count, frames_to_read);
+
+ /* Ready for more data */
+ buff = (uint8_t *) areas->addr +
+ (areas->first + areas->step * offset) / 8;
+ memcpy(data->buffer + data->count, buff, frame_size * frames_to_read);
+
+ /* Remember we have some frames in the pipe now */
+ data->count += frames_to_read * frame_size;
+ if (data->count != data->link_mtu) {
+ ret = frames_to_read;
+ goto done;
+ }
+
+ rsend = send(data->stream.fd, data->buffer, data->link_mtu,
+ io->nonblock ? MSG_DONTWAIT : 0);
+ if (rsend > 0) {
+ /* Reset count pointer */
+ data->count = 0;
+
+ ret = frames_to_read;
+ } else if (rsend < 0)
+ ret = (errno == EPIPE) ? -EIO : -errno;
+ else
+ ret = -EIO;
+
+done:
+ DBG("returning %ld", ret);
+ return ret;
+}
+
+static snd_pcm_sframes_t bluetooth_a2dp_read(snd_pcm_ioplug_t *io,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
+{
+ snd_pcm_uframes_t ret = 0;
+ return ret;
+}
+
+static int avdtp_write(struct bluetooth_data *data)
+{
+ int ret = 0;
+ struct rtp_header *header;
+ struct rtp_payload *payload;
+ struct bluetooth_a2dp *a2dp = &data->a2dp;
+
+ header = (void *) a2dp->buffer;
+ payload = (void *) (a2dp->buffer + sizeof(*header));
+
+ memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload));
+
+ payload->frame_count = a2dp->frame_count;
+ header->v = 2;
+ header->pt = 1;
+ header->sequence_number = htons(a2dp->seq_num);
+ header->timestamp = htonl(a2dp->nsamples);
+ header->ssrc = htonl(1);
+
+ ret = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT);
+ if (ret < 0) {
+ DBG("send returned %d errno %s.", ret, strerror(errno));
+ ret = -errno;
+ }
+
+ /* Reset buffer of data to send */
+ a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+ a2dp->frame_count = 0;
+ a2dp->samples = 0;
+ a2dp->seq_num++;
+
+ return ret;
+}
+
+static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
+{
+ struct bluetooth_data *data = io->private_data;
+ struct bluetooth_a2dp *a2dp = &data->a2dp;
+ snd_pcm_sframes_t ret = 0;
+ snd_pcm_uframes_t frames_to_read, frames_left = size;
+ int frame_size, encoded, written;
+ uint8_t *buff;
+
+ DBG("areas->step=%u areas->first=%u offset=%lu size=%lu",
+ areas->step, areas->first, offset, size);
+ DBG("hw_ptr=%lu appl_ptr=%lu diff=%lu", io->hw_ptr, io->appl_ptr,
+ io->appl_ptr - io->hw_ptr);
+
+ if (io->hw_ptr > io->appl_ptr) {
+ ret = bluetooth_playback_stop(io);
+ if (ret == 0)
+ ret = -EPIPE;
+ data->reset = 1;
+ goto done;
+ }
+
+ /* Check if we should autostart */
+ if (io->state == SND_PCM_STATE_PREPARED) {
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_uframes_t threshold;
+
+ snd_pcm_sw_params_malloc(&swparams);
+ if (!snd_pcm_sw_params_current(io->pcm, swparams) &&
+ !snd_pcm_sw_params_get_start_threshold(swparams,
+ &threshold)) {
+ if (io->appl_ptr >= threshold) {
+ ret = snd_pcm_start(io->pcm);
+ if (ret != 0)
+ goto done;
+ }
+ }
+
+ snd_pcm_sw_params_free(swparams);
+ }
+
+ while (frames_left > 0) {
+ frame_size = areas->step / 8;
+
+ if ((data->count + frames_left * frame_size) <= a2dp->codesize)
+ frames_to_read = frames_left;
+ else
+ frames_to_read = (a2dp->codesize - data->count) / frame_size;
+
+ DBG("count=%d frames_to_read=%lu", data->count, frames_to_read);
+ DBG("a2dp.count=%d data.link_mtu=%d", a2dp->count, data->link_mtu);
+
+ /* FIXME: If state is not streaming then return */
+
+ /* Ready for more data */
+ buff = (uint8_t *) areas->addr +
+ (areas->first + areas->step * (offset + ret)) / 8;
+ memcpy(data->buffer + data->count, buff,
+ frame_size * frames_to_read);
+
+ /* Remember we have some frames in the pipe now */
+ data->count += frames_to_read * frame_size;
+ if (data->count != a2dp->codesize) {
+ ret = frames_to_read;
+ goto done;
+ }
+
+ /* Enough data to encode (sbc wants 1k blocks) */
+ encoded = sbc_encode(&(a2dp->sbc), data->buffer, a2dp->codesize,
+ a2dp->buffer + a2dp->count,
+ sizeof(a2dp->buffer) - a2dp->count,
+ &written);
+ if (encoded <= 0) {
+ DBG("Encoding error %d", encoded);
+ goto done;
+ }
+
+ data->count -= encoded;
+ a2dp->count += written;
+ a2dp->frame_count++;
+ a2dp->samples += encoded / frame_size;
+ a2dp->nsamples += encoded / frame_size;
+
+ DBG("encoded=%d written=%d count=%d", encoded,
+ written, a2dp->count);
+
+ /* No space left for another frame then send */
+ if (a2dp->count + written >= data->link_mtu) {
+ avdtp_write(data);
+ DBG("sending packet %d, count %d, link_mtu %u",
+ a2dp->seq_num, a2dp->count,
+ data->link_mtu);
+ }
+
+ ret += frames_to_read;
+ frames_left -= frames_to_read;
+ }
+
+ /* note: some ALSA apps will get confused otherwise */
+ if (ret > size)
+ ret = size;
+
+done:
+ DBG("returning %ld", ret);
+ return ret;
+}
+
+static int bluetooth_playback_delay(snd_pcm_ioplug_t *io,
+ snd_pcm_sframes_t *delayp)
+{
+ DBG("");
+
+ /* This updates io->hw_ptr value using pointer() function */
+ snd_pcm_hwsync(io->pcm);
+
+ *delayp = io->appl_ptr - io->hw_ptr;
+ if ((io->state == SND_PCM_STATE_RUNNING) && (*delayp < 0)) {
+ io->callback->stop(io);
+ io->state = SND_PCM_STATE_XRUN;
+ *delayp = 0;
+ }
+
+ /* This should never fail, ALSA API is really not
+ prepared to handle a non zero return value */
+ return 0;
+}
+
+static snd_pcm_ioplug_callback_t bluetooth_hsp_playback = {
+ .start = bluetooth_playback_start,
+ .stop = bluetooth_playback_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_hsp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_hsp_write,
+ .poll_descriptors_count = bluetooth_playback_poll_descriptors_count,
+ .poll_descriptors = bluetooth_playback_poll_descriptors,
+ .poll_revents = bluetooth_playback_poll_revents,
+ .delay = bluetooth_playback_delay,
+};
+
+static snd_pcm_ioplug_callback_t bluetooth_hsp_capture = {
+ .start = bluetooth_start,
+ .stop = bluetooth_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_hsp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_hsp_read,
+ .poll_descriptors = bluetooth_poll_descriptors,
+ .poll_revents = bluetooth_poll_revents,
+};
+
+static snd_pcm_ioplug_callback_t bluetooth_a2dp_playback = {
+ .start = bluetooth_playback_start,
+ .stop = bluetooth_playback_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_a2dp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_a2dp_write,
+ .poll_descriptors_count = bluetooth_playback_poll_descriptors_count,
+ .poll_descriptors = bluetooth_playback_poll_descriptors,
+ .poll_revents = bluetooth_playback_poll_revents,
+ .delay = bluetooth_playback_delay,
+};
+
+static snd_pcm_ioplug_callback_t bluetooth_a2dp_capture = {
+ .start = bluetooth_start,
+ .stop = bluetooth_stop,
+ .pointer = bluetooth_pointer,
+ .close = bluetooth_close,
+ .hw_params = bluetooth_a2dp_hw_params,
+ .prepare = bluetooth_prepare,
+ .transfer = bluetooth_a2dp_read,
+ .poll_descriptors = bluetooth_poll_descriptors,
+ .poll_revents = bluetooth_poll_revents,
+};
+
+#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
+
+static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+ snd_pcm_access_t access_list[] = {
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ /* Mmap access is really useless fo this driver, but we
+ * support it because some pieces of software out there
+ * insist on using it */
+ SND_PCM_ACCESS_MMAP_INTERLEAVED
+ };
+ unsigned int format_list[] = {
+ SND_PCM_FORMAT_S16_LE
+ };
+ int err;
+
+ /* access type */
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
+ ARRAY_NELEMS(access_list), access_list);
+ if (err < 0)
+ return err;
+
+ /* supported formats */
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
+ ARRAY_NELEMS(format_list), format_list);
+ if (err < 0)
+ return err;
+
+ /* supported channels */
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
+ 1, 1);
+ if (err < 0)
+ return err;
+
+ /* supported rate */
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
+ 8000, 8000);
+ if (err < 0)
+ return err;
+
+ /* supported block size */
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
+ data->link_mtu, data->link_mtu);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
+ 2, 200);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+ struct bluetooth_a2dp *a2dp = &data->a2dp;
+ struct bluetooth_alsa_config *cfg = &data->alsa_config;
+ snd_pcm_access_t access_list[] = {
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ /* Mmap access is really useless fo this driver, but we
+ * support it because some pieces of software out there
+ * insist on using it */
+ SND_PCM_ACCESS_MMAP_INTERLEAVED
+ };
+ unsigned int format_list[] = {
+ SND_PCM_FORMAT_S16_LE
+ };
+ unsigned int rate_list[4];
+ unsigned int rate_count;
+ int err, min_channels, max_channels;
+ unsigned int period_list[] = {
+ 2048,
+ 4096, /* e.g. 23.2msec/period (stereo 16bit at 44.1kHz) */
+ 8192
+ };
+
+ /* access type */
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
+ ARRAY_NELEMS(access_list), access_list);
+ if (err < 0)
+ return err;
+
+ /* supported formats */
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
+ ARRAY_NELEMS(format_list), format_list);
+ if (err < 0)
+ return err;
+
+ /* supported channels */
+ if (cfg->has_channel_mode)
+ a2dp->sbc_capabilities.channel_mode = cfg->channel_mode;
+
+ if (a2dp->sbc_capabilities.channel_mode &
+ BT_A2DP_CHANNEL_MODE_MONO)
+ min_channels = 1;
+ else
+ min_channels = 2;
+
+ if (a2dp->sbc_capabilities.channel_mode &
+ (~BT_A2DP_CHANNEL_MODE_MONO))
+ max_channels = 2;
+ else
+ max_channels = 1;
+
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
+ min_channels, max_channels);
+ if (err < 0)
+ return err;
+
+ /* supported buffer sizes
+ * (can be used as 3*8192, 6*4096, 12*2048, ...) */
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_BUFFER_BYTES,
+ 8192*3, 8192*3);
+ if (err < 0)
+ return err;
+
+ /* supported block sizes: */
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
+ ARRAY_NELEMS(period_list), period_list);
+ if (err < 0)
+ return err;
+
+ /* supported rates */
+ rate_count = 0;
+ if (cfg->has_rate) {
+ rate_list[rate_count] = cfg->rate;
+ rate_count++;
+ } else {
+ if (a2dp->sbc_capabilities.frequency &
+ BT_SBC_SAMPLING_FREQ_16000) {
+ rate_list[rate_count] = 16000;
+ rate_count++;
+ }
+
+ if (a2dp->sbc_capabilities.frequency &
+ BT_SBC_SAMPLING_FREQ_32000) {
+ rate_list[rate_count] = 32000;
+ rate_count++;
+ }
+
+ if (a2dp->sbc_capabilities.frequency &
+ BT_SBC_SAMPLING_FREQ_44100) {
+ rate_list[rate_count] = 44100;
+ rate_count++;
+ }
+
+ if (a2dp->sbc_capabilities.frequency &
+ BT_SBC_SAMPLING_FREQ_48000) {
+ rate_list[rate_count] = 48000;
+ rate_count++;
+ }
+ }
+
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE,
+ rate_count, rate_list);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int bluetooth_parse_config(snd_config_t *conf,
+ struct bluetooth_alsa_config *bt_config)
+{
+ snd_config_iterator_t i, next;
+
+ memset(bt_config, 0, sizeof(struct bluetooth_alsa_config));
+
+ /* Set defaults */
+ bt_config->autoconnect = 1;
+
+ snd_config_for_each(i, next, conf) {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ const char *id, *value;
+
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
+
+ if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
+ continue;
+
+ if (strcmp(id, "autoconnect") == 0) {
+ int b;
+
+ b = snd_config_get_bool(n);
+ if (b < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ bt_config->autoconnect = b;
+ continue;
+ }
+
+ if (strcmp(id, "device") == 0 || strcmp(id, "bdaddr") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ bt_config->has_device = 1;
+ strncpy(bt_config->device, value, 18);
+ continue;
+ }
+
+ if (strcmp(id, "profile") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ if (strcmp(value, "auto") == 0) {
+ bt_config->transport = BT_CAPABILITIES_TRANSPORT_ANY;
+ bt_config->has_transport = 1;
+ } else if (strcmp(value, "voice") == 0 ||
+ strcmp(value, "hfp") == 0) {
+ bt_config->transport = BT_CAPABILITIES_TRANSPORT_SCO;
+ bt_config->has_transport = 1;
+ } else if (strcmp(value, "hifi") == 0 ||
+ strcmp(value, "a2dp") == 0) {
+ bt_config->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
+ bt_config->has_transport = 1;
+ }
+ continue;
+ }
+
+ if (strcmp(id, "rate") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ bt_config->rate = atoi(value);
+ bt_config->has_rate = 1;
+ continue;
+ }
+
+ if (strcmp(id, "mode") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ if (strcmp(value, "mono") == 0) {
+ bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
+ bt_config->has_channel_mode = 1;
+ } else if (strcmp(value, "dual") == 0) {
+ bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
+ bt_config->has_channel_mode = 1;
+ } else if (strcmp(value, "stereo") == 0) {
+ bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
+ bt_config->has_channel_mode = 1;
+ } else if (strcmp(value, "joint") == 0) {
+ bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+ bt_config->has_channel_mode = 1;
+ }
+ continue;
+ }
+
+ if (strcmp(id, "allocation") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ if (strcmp(value, "loudness") == 0) {
+ bt_config->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
+ bt_config->has_allocation_method = 1;
+ } else if (strcmp(value, "snr") == 0) {
+ bt_config->allocation_method = BT_A2DP_ALLOCATION_SNR;
+ bt_config->has_allocation_method = 1;
+ }
+ continue;
+ }
+
+ if (strcmp(id, "subbands") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ bt_config->subbands = atoi(value);
+ bt_config->has_subbands = 1;
+ continue;
+ }
+
+ if (strcmp(id, "blocks") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ bt_config->block_length = atoi(value);
+ bt_config->has_block_length = 1;
+ continue;
+ }
+
+ if (strcmp(id, "bitpool") == 0) {
+ if (snd_config_get_string(n, &value) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+
+ bt_config->bitpool = atoi(value);
+ bt_config->has_bitpool = 1;
+ continue;
+ }
+
+ SNDERR("Unknown field %s", id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int audioservice_send(int sk, const bt_audio_msg_header_t *msg)
+{
+ int err;
+
+ DBG("sending %s", bt_audio_strmsg(msg->msg_type));
+ if (send(sk, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0)
+ err = 0;
+ else {
+ err = -errno;
+ SNDERR("Error sending data to audio service: %s(%d)",
+ strerror(errno), errno);
+ }
+
+ return err;
+}
+
+static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg)
+{
+ int err;
+ const char *type;
+
+ DBG("trying to receive msg from audio service...");
+ if (recv(sk, inmsg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) {
+ type = bt_audio_strmsg(inmsg->msg_type);
+ if (type) {
+ DBG("Received %s", type);
+ err = 0;
+ } else {
+ err = -EINVAL;
+ SNDERR("Bogus message type %d "
+ "received from audio service",
+ inmsg->msg_type);
+ }
+ } else {
+ err = -errno;
+ SNDERR("Error receiving data from audio service: %s(%d)",
+ strerror(errno), errno);
+ }
+
+ return err;
+}
+
+static int audioservice_expect(int sk, bt_audio_msg_header_t *rsp_hdr,
+ int expected_type)
+{
+ int err = audioservice_recv(sk, rsp_hdr);
+ if (err == 0) {
+ if (rsp_hdr->msg_type != expected_type) {
+ err = -EINVAL;
+ SNDERR("Bogus message %s received while "
+ "%s was expected",
+ bt_audio_strmsg(rsp_hdr->msg_type),
+ bt_audio_strmsg(expected_type));
+ }
+ }
+ return err;
+}
+
+static int bluetooth_init(struct bluetooth_data *data, snd_pcm_stream_t stream,
+ snd_config_t *conf)
+{
+ int sk, err;
+ struct bluetooth_alsa_config *alsa_conf = &data->alsa_config;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf;
+ struct bt_getcapabilities_req *getcaps_req = (void*) buf;
+ struct bt_getcapabilities_rsp *getcaps_rsp = (void*) buf;
+
+ memset(data, 0, sizeof(struct bluetooth_data));
+
+ err = bluetooth_parse_config(conf, alsa_conf);
+ if (err < 0)
+ return err;
+
+ data->server.fd = -1;
+ data->stream.fd = -1;
+
+ sk = bt_audio_service_open();
+ if (sk <= 0) {
+ err = -errno;
+ goto failed;
+ }
+
+ data->server.fd = sk;
+ data->server.events = POLLIN;
+
+ data->pipefd[0] = -1;
+ data->pipefd[1] = -1;
+
+ if (pipe(data->pipefd) < 0) {
+ err = -errno;
+ goto failed;
+ }
+ if (fcntl(data->pipefd[0], F_SETFL, O_NONBLOCK) < 0) {
+ err = -errno;
+ goto failed;
+ }
+ if (fcntl(data->pipefd[1], F_SETFL, O_NONBLOCK) < 0) {
+ err = -errno;
+ goto failed;
+ }
+
+ memset(getcaps_req, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ getcaps_req->h.msg_type = BT_GETCAPABILITIES_REQ;
+ getcaps_req->flags = 0;
+ if (alsa_conf->autoconnect)
+ getcaps_req->flags |= BT_FLAG_AUTOCONNECT;
+ strncpy(getcaps_req->device, alsa_conf->device, 18);
+ if (alsa_conf->has_transport)
+ getcaps_req->transport = alsa_conf->transport;
+ else
+ getcaps_req->transport = BT_CAPABILITIES_TRANSPORT_ANY;
+
+ err = audioservice_send(data->server.fd, &getcaps_req->h);
+ if (err < 0)
+ goto failed;
+
+ err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h, BT_GETCAPABILITIES_RSP);
+ if (err < 0)
+ goto failed;
+
+ if (rsp_hdr->posix_errno != 0) {
+ SNDERR("BT_GETCAPABILITIES failed : %s(%d)",
+ strerror(rsp_hdr->posix_errno),
+ rsp_hdr->posix_errno);
+ return -rsp_hdr->posix_errno;
+ }
+
+ data->transport = getcaps_rsp->transport;
+
+ if (getcaps_rsp->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
+ data->a2dp.sbc_capabilities = getcaps_rsp->sbc_capabilities;
+
+ return 0;
+
+failed:
+ bt_audio_service_close(sk);
+ return err;
+}
+
+SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
+{
+ struct bluetooth_data *data;
+ int err;
+
+ DBG("Bluetooth PCM plugin (%s)",
+ stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
+
+ data = malloc(sizeof(struct bluetooth_data));
+ if (!data) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ err = bluetooth_init(data, stream, conf);
+ if (err < 0)
+ goto error;
+
+ data->io.version = SND_PCM_IOPLUG_VERSION;
+ data->io.name = "Bluetooth Audio Device";
+ data->io.mmap_rw = 0; /* No direct mmap communication */
+ data->io.private_data = data;
+
+ if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
+ data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
+ &bluetooth_a2dp_playback :
+ &bluetooth_a2dp_capture;
+ else
+ data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
+ &bluetooth_hsp_playback :
+ &bluetooth_hsp_capture;
+
+ err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
+ if (err < 0)
+ goto error;
+
+ if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
+ err = bluetooth_a2dp_hw_constraint(&data->io);
+ else
+ err = bluetooth_hsp_hw_constraint(&data->io);
+
+ if (err < 0) {
+ snd_pcm_ioplug_delete(&data->io);
+ goto error;
+ }
+
+ *pcmp = data->io.pcm;
+
+ return 0;
+
+error:
+ bluetooth_exit(data);
+
+ return err;
+}
+
+SND_PCM_PLUGIN_SYMBOL(bluetooth);
diff --git a/utils/audio/rtp.h b/utils/audio/rtp.h
new file mode 100644
index 00000000..690bd43a
--- /dev/null
+++ b/utils/audio/rtp.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_header {
+ uint8_t cc:4;
+ uint8_t x:1;
+ uint8_t p:1;
+ uint8_t v:2;
+
+ uint8_t pt:7;
+ uint8_t m:1;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+struct rtp_payload {
+ uint8_t frame_count:4;
+ uint8_t rfa0:1;
+ uint8_t is_last_fragment:1;
+ uint8_t is_first_fragment:1;
+ uint8_t is_fragmented:1;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct rtp_header {
+ uint8_t v:2;
+ uint8_t p:1;
+ uint8_t x:1;
+ uint8_t cc:4;
+
+ uint8_t m:1;
+ uint8_t pt:7;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+struct rtp_payload {
+ uint8_t is_fragmented:1;
+ uint8_t is_first_fragment:1;
+ uint8_t is_last_fragment:1;
+ uint8_t rfa0:1;
+ uint8_t frame_count:4;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
diff --git a/utils/audio/sink.c b/utils/audio/sink.c
new file mode 100644
index 00000000..2af74bb3
--- /dev/null
+++ b/utils/audio/sink.c
@@ -0,0 +1,563 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "logging.h"
+
+#include "avdtp.h"
+#include "device.h"
+#include "a2dp.h"
+#include "error.h"
+#include "sink.h"
+
+#define STREAM_SETUP_RETRY_TIMER 2000
+
+struct pending_request {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ unsigned int id;
+};
+
+struct sink {
+ struct avdtp *session;
+ struct avdtp_stream *stream;
+ unsigned int cb_id;
+ uint8_t state;
+ struct pending_request *connect;
+ struct pending_request *disconnect;
+ DBusConnection *conn;
+};
+
+static void pending_request_free(struct pending_request *pending)
+{
+ if (pending->conn)
+ dbus_connection_unref(pending->conn);
+ if (pending->msg)
+ dbus_message_unref(pending->msg);
+ g_free(pending);
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+ avdtp_state_t old_state,
+ avdtp_state_t new_state,
+ struct avdtp_error *err,
+ void *user_data)
+{
+ struct audio_device *dev = user_data;
+ struct sink *sink = dev->sink;
+
+ if (err)
+ return;
+
+ switch (new_state) {
+ case AVDTP_STATE_IDLE:
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_SINK_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+ if (sink->disconnect) {
+ DBusMessage *reply;
+ struct pending_request *p;
+
+ p = sink->disconnect;
+ sink->disconnect = NULL;
+
+ reply = dbus_message_new_method_return(p->msg);
+ dbus_connection_send(p->conn, reply, NULL);
+ dbus_message_unref(reply);
+ pending_request_free(p);
+ }
+
+ if (sink->session) {
+ avdtp_unref(sink->session);
+ sink->session = NULL;
+ }
+ sink->stream = NULL;
+ sink->cb_id = 0;
+ break;
+ case AVDTP_STATE_OPEN:
+ if (old_state == AVDTP_STATE_CONFIGURED)
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_SINK_INTERFACE,
+ "Connected",
+ DBUS_TYPE_INVALID);
+ else if (old_state == AVDTP_STATE_STREAMING)
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_SINK_INTERFACE,
+ "Stopped",
+ DBUS_TYPE_INVALID);
+ break;
+ case AVDTP_STATE_STREAMING:
+ g_dbus_emit_signal(dev->conn, dev->path,
+ AUDIO_SINK_INTERFACE,
+ "Playing",
+ DBUS_TYPE_INVALID);
+ break;
+ case AVDTP_STATE_CONFIGURED:
+ case AVDTP_STATE_CLOSING:
+ case AVDTP_STATE_ABORTING:
+ default:
+ break;
+ }
+
+ sink->state = new_state;
+}
+
+static gboolean stream_setup_retry(gpointer user_data)
+{
+ struct sink *sink = user_data;
+ struct pending_request *pending = sink->connect;
+
+ if (sink->state >= AVDTP_STATE_OPEN) {
+ DBusMessage *reply;
+ debug("Stream successfully created, after XCASE connect:connect");
+ reply = dbus_message_new_method_return(pending->msg);
+ dbus_connection_send(pending->conn, reply, NULL);
+ dbus_message_unref(reply);
+ } else {
+ debug("Stream setup failed, after XCASE connect:connect");
+ error_failed(pending->conn, pending->msg, "Stream setup failed");
+ }
+
+ sink->connect = NULL;
+ pending_request_free(pending);
+
+ return FALSE;
+}
+
+static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err, void *user_data)
+{
+ struct sink *sink = user_data;
+ struct pending_request *pending;
+
+ pending = sink->connect;
+
+ if (stream) {
+ DBusMessage *reply;
+ sink->connect = NULL;
+ reply = dbus_message_new_method_return(pending->msg);
+ dbus_connection_send(pending->conn, reply, NULL);
+ dbus_message_unref(reply);
+ pending_request_free(pending);
+ debug("Stream successfully created");
+ } else {
+ avdtp_unref(sink->session);
+ sink->session = NULL;
+ if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
+ && avdtp_error_posix_errno(err) != EHOSTDOWN) {
+ debug("connect:connect XCASE detected");
+ g_timeout_add(STREAM_SETUP_RETRY_TIMER,
+ stream_setup_retry, sink);
+ } else {
+ sink->connect = NULL;
+ error_failed(pending->conn, pending->msg, "Stream setup failed");
+ pending_request_free(pending);
+ debug("Stream setup failed : %s", avdtp_strerror(err));
+ }
+ }
+}
+
+static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
+{
+ switch (freq) {
+ case SBC_SAMPLING_FREQ_16000:
+ case SBC_SAMPLING_FREQ_32000:
+ return 53;
+ case SBC_SAMPLING_FREQ_44100:
+ switch (mode) {
+ case SBC_CHANNEL_MODE_MONO:
+ case SBC_CHANNEL_MODE_DUAL_CHANNEL:
+ return 31;
+ case SBC_CHANNEL_MODE_STEREO:
+ case SBC_CHANNEL_MODE_JOINT_STEREO:
+ return 53;
+ default:
+ error("Invalid channel mode %u", mode);
+ return 53;
+ }
+ case SBC_SAMPLING_FREQ_48000:
+ switch (mode) {
+ case SBC_CHANNEL_MODE_MONO:
+ case SBC_CHANNEL_MODE_DUAL_CHANNEL:
+ return 29;
+ case SBC_CHANNEL_MODE_STEREO:
+ case SBC_CHANNEL_MODE_JOINT_STEREO:
+ return 51;
+ default:
+ error("Invalid channel mode %u", mode);
+ return 51;
+ }
+ default:
+ error("Invalid sampling freq %u", freq);
+ return 53;
+ }
+}
+
+static gboolean select_sbc_params(struct sbc_codec_cap *cap,
+ struct sbc_codec_cap *supported)
+{
+ unsigned int max_bitpool, min_bitpool;
+
+ memset(cap, 0, sizeof(struct sbc_codec_cap));
+
+ cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ cap->cap.media_codec_type = A2DP_CODEC_SBC;
+
+ if (supported->frequency & SBC_SAMPLING_FREQ_44100)
+ cap->frequency = SBC_SAMPLING_FREQ_44100;
+ else if (supported->frequency & SBC_SAMPLING_FREQ_48000)
+ cap->frequency = SBC_SAMPLING_FREQ_48000;
+ else if (supported->frequency & SBC_SAMPLING_FREQ_32000)
+ cap->frequency = SBC_SAMPLING_FREQ_32000;
+ else if (supported->frequency & SBC_SAMPLING_FREQ_16000)
+ cap->frequency = SBC_SAMPLING_FREQ_16000;
+ else {
+ error("No supported frequencies");
+ return FALSE;
+ }
+
+ if (supported->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
+ cap->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
+ else if (supported->channel_mode & SBC_CHANNEL_MODE_STEREO)
+ cap->channel_mode = SBC_CHANNEL_MODE_STEREO;
+ else if (supported->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
+ cap->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
+ else if (supported->channel_mode & SBC_CHANNEL_MODE_MONO)
+ cap->channel_mode = SBC_CHANNEL_MODE_MONO;
+ else {
+ error("No supported channel modes");
+ return FALSE;
+ }
+
+ if (supported->block_length & SBC_BLOCK_LENGTH_16)
+ cap->block_length = SBC_BLOCK_LENGTH_16;
+ else if (supported->block_length & SBC_BLOCK_LENGTH_12)
+ cap->block_length = SBC_BLOCK_LENGTH_12;
+ else if (supported->block_length & SBC_BLOCK_LENGTH_8)
+ cap->block_length = SBC_BLOCK_LENGTH_8;
+ else if (supported->block_length & SBC_BLOCK_LENGTH_4)
+ cap->block_length = SBC_BLOCK_LENGTH_4;
+ else {
+ error("No supported block lengths");
+ return FALSE;
+ }
+
+ if (supported->subbands & SBC_SUBBANDS_8)
+ cap->subbands = SBC_SUBBANDS_8;
+ else if (supported->subbands & SBC_SUBBANDS_4)
+ cap->subbands = SBC_SUBBANDS_4;
+ else {
+ error("No supported subbands");
+ return FALSE;
+ }
+
+ if (supported->allocation_method & SBC_ALLOCATION_LOUDNESS)
+ cap->allocation_method = SBC_ALLOCATION_LOUDNESS;
+ else if (supported->allocation_method & SBC_ALLOCATION_SNR)
+ cap->allocation_method = SBC_ALLOCATION_SNR;
+
+ min_bitpool = MAX(MIN_BITPOOL, supported->min_bitpool);
+ max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode),
+ supported->max_bitpool);
+
+ cap->min_bitpool = min_bitpool;
+ cap->max_bitpool = max_bitpool;
+
+ return TRUE;
+}
+
+static gboolean select_capabilities(struct avdtp *session,
+ struct avdtp_remote_sep *rsep,
+ GSList **caps)
+{
+ struct avdtp_service_capability *media_transport, *media_codec;
+ struct sbc_codec_cap sbc_cap;
+
+ media_codec = avdtp_get_codec(rsep);
+ if (!media_codec)
+ return FALSE;
+
+ select_sbc_params(&sbc_cap, (struct sbc_codec_cap *) media_codec->data);
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ *caps = g_slist_append(*caps, media_transport);
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
+ sizeof(sbc_cap));
+
+ *caps = g_slist_append(*caps, media_codec);
+
+
+ return TRUE;
+}
+
+static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
+ void *user_data)
+{
+ struct sink *sink = user_data;
+ struct pending_request *pending;
+ struct avdtp_local_sep *lsep;
+ struct avdtp_remote_sep *rsep;
+ GSList *caps = NULL;
+ int id;
+
+ pending = sink->connect;
+
+ if (err) {
+ avdtp_unref(sink->session);
+ sink->session = NULL;
+ if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
+ && avdtp_error_posix_errno(err) != EHOSTDOWN) {
+ debug("connect:connect XCASE detected");
+ g_timeout_add(STREAM_SETUP_RETRY_TIMER,
+ stream_setup_retry, sink);
+ } else
+ goto failed;
+ return;
+ }
+
+ debug("Discovery complete");
+
+ if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
+ A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
+ error("No matching ACP and INT SEPs found");
+ goto failed;
+ }
+
+ if (!select_capabilities(session, rsep, &caps)) {
+ error("Unable to select remote SEP capabilities");
+ goto failed;
+ }
+
+ id = a2dp_source_config(sink->session, stream_setup_complete,
+ caps, sink);
+ if (id == 0)
+ goto failed;
+
+ pending->id = id;
+ return;
+
+failed:
+ pending_request_free(pending);
+ sink->connect = NULL;
+ avdtp_unref(sink->session);
+ sink->session = NULL;
+ error_failed(pending->conn, pending->msg, "Stream setup failed");
+}
+
+static DBusMessage *sink_connect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct audio_device *dev = data;
+ struct sink *sink = dev->sink;
+ struct pending_request *pending;
+
+ if (!sink->session)
+ sink->session = avdtp_get(&dev->src, &dev->dst);
+
+ if (!sink->session)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Unable to get a session");
+
+ if (sink->connect || sink->disconnect)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", strerror(EBUSY));
+
+ if (sink->state >= AVDTP_STATE_OPEN)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".AlreadyConnected",
+ "Device Already Connected");
+
+ pending = g_new0(struct pending_request, 1);
+ pending->conn = dbus_connection_ref(conn);
+ pending->msg = dbus_message_ref(msg);
+ sink->connect = pending;
+
+ avdtp_discover(sink->session, discovery_complete, sink);
+
+ debug("stream creation in progress");
+
+ return NULL;
+}
+
+static DBusMessage *sink_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct audio_device *device = data;
+ struct sink *sink = device->sink;
+ struct pending_request *pending;
+ int err;
+
+ if (!sink->session)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".NotConnected",
+ "Device not Connected");
+
+ if (sink->connect || sink->disconnect)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", strerror(EBUSY));
+
+ if (sink->state < AVDTP_STATE_OPEN) {
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+ avdtp_unref(sink->session);
+ sink->session = NULL;
+ return reply;
+ }
+
+ err = avdtp_close(sink->session, sink->stream);
+ if (err < 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "%s", strerror(-err));
+
+ pending = g_new0(struct pending_request, 1);
+ pending->conn = dbus_connection_ref(conn);
+ pending->msg = dbus_message_ref(msg);
+ sink->disconnect = pending;
+
+ return NULL;
+}
+
+static DBusMessage *sink_is_connected(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ struct sink *sink = device->sink;
+ DBusMessage *reply;
+ dbus_bool_t connected;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ connected = (sink->state >= AVDTP_STATE_CONFIGURED);
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static GDBusMethodTable sink_methods[] = {
+ { "Connect", "", "", sink_connect,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "Disconnect", "", "", sink_disconnect,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "IsConnected", "", "b", sink_is_connected },
+ { NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable sink_signals[] = {
+ { "Connected", "" },
+ { "Disconnected", "" },
+ { "Playing", "" },
+ { "Stopped", "" },
+ { NULL, NULL }
+};
+
+struct sink *sink_init(struct audio_device *dev)
+{
+ if (!g_dbus_register_interface(dev->conn, dev->path,
+ AUDIO_SINK_INTERFACE,
+ sink_methods, sink_signals, NULL,
+ dev, NULL))
+ return NULL;
+
+ return g_new0(struct sink, 1);
+}
+
+void sink_free(struct audio_device *dev)
+{
+ struct sink *sink = dev->sink;
+
+ if (sink->cb_id)
+ avdtp_stream_remove_cb(sink->session, sink->stream,
+ sink->cb_id);
+
+ if (sink->session)
+ avdtp_unref(sink->session);
+
+ if (sink->connect)
+ pending_request_free(sink->connect);
+
+ if (sink->disconnect)
+ pending_request_free(sink->disconnect);
+
+ g_free(sink);
+ dev->sink = NULL;
+}
+
+gboolean sink_is_active(struct audio_device *dev)
+{
+ struct sink *sink = dev->sink;
+
+ if (sink->session)
+ return TRUE;
+
+ return FALSE;
+}
+
+avdtp_state_t sink_get_state(struct audio_device *dev)
+{
+ struct sink *sink = dev->sink;
+
+ return sink->state;
+}
+
+gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
+ struct avdtp_stream *stream)
+{
+ struct sink *sink = dev->sink;
+
+ if (sink->stream)
+ return FALSE;
+
+ if (!sink->session)
+ sink->session = avdtp_ref(session);
+
+ sink->stream = stream;
+
+ sink->cb_id = avdtp_stream_add_cb(session, stream,
+ stream_state_changed, dev);
+
+ return TRUE;
+}
diff --git a/utils/audio/sink.h b/utils/audio/sink.h
new file mode 100644
index 00000000..5e4b6aaa
--- /dev/null
+++ b/utils/audio/sink.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define AUDIO_SINK_INTERFACE "org.bluez.audio.Sink"
+
+struct sink *sink_init(struct audio_device *dev);
+void sink_free(struct audio_device *dev);
+gboolean sink_is_active(struct audio_device *dev);
+avdtp_state_t sink_get_state(struct audio_device *dev);
+gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
+ struct avdtp_stream *stream);
diff --git a/utils/audio/test-audio b/utils/audio/test-audio
new file mode 100755
index 00000000..19ea6252
--- /dev/null
+++ b/utils/audio/test-audio
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Manager')
+
+conn = manager.ActivateService('audio')
+
+audio = dbus.Interface(bus.get_object(conn, '/org/bluez/audio'),
+ 'org.bluez.audio.Manager')
+
+try:
+ headset = dbus.Interface(bus.get_object(conn, audio.DefaultHeadset()),
+ 'org.bluez.audio.Headset')
+except:
+ pass
+
+try:
+ device = dbus.Interface(bus.get_object(conn, audio.DefaultDevice()),
+ 'org.bluez.audio.Device')
+ sink = dbus.Interface(bus.get_object(conn, audio.DefaultDevice()),
+ 'org.bluez.audio.Sink')
+except:
+ pass
diff --git a/utils/audio/unix.c b/utils/audio/unix.c
new file mode 100644
index 00000000..93f5788b
--- /dev/null
+++ b/utils/audio/unix.c
@@ -0,0 +1,1155 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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 <sys/socket.h>
+#include <sys/un.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <dbus/dbus.h>
+#include <glib.h>
+
+#include "logging.h"
+#include "ipc.h"
+#include "device.h"
+#include "manager.h"
+#include "avdtp.h"
+#include "a2dp.h"
+#include "headset.h"
+#include "sink.h"
+#include "unix.h"
+#include "glib-helper.h"
+
+typedef enum {
+ TYPE_NONE,
+ TYPE_HEADSET,
+ TYPE_SINK,
+ TYPE_SOURCE
+} service_type_t;
+
+typedef void (*notify_cb_t) (struct audio_device *dev, void *data);
+
+struct a2dp_data {
+ struct avdtp *session;
+ struct avdtp_stream *stream;
+ struct a2dp_sep *sep;
+};
+
+struct headset_data {
+ headset_lock_t lock;
+};
+
+struct unix_client {
+ struct audio_device *dev;
+ GSList *caps;
+ service_type_t type;
+ char *interface;
+ union {
+ struct a2dp_data a2dp;
+ struct headset_data hs;
+ } d;
+ int sock;
+ int access_mode;
+ int data_fd; /* To be deleted once two phase configuration is fully implemented */
+ unsigned int req_id;
+ unsigned int cb_id;
+ gboolean (*cancel) (struct audio_device *dev, unsigned int id);
+};
+
+static GSList *clients = NULL;
+
+static int unix_sock = -1;
+
+static void client_free(struct unix_client *client)
+{
+ struct a2dp_data *a2dp;
+
+ switch (client->type) {
+ case TYPE_SINK:
+ case TYPE_SOURCE:
+ a2dp = &client->d.a2dp;
+ if (client->cb_id > 0)
+ avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
+ client->cb_id);
+ if (a2dp->sep)
+ a2dp_sep_unlock(a2dp->sep, a2dp->session);
+ if (a2dp->session)
+ avdtp_unref(a2dp->session);
+ break;
+ default:
+ break;
+ }
+
+ if (client->sock >= 0)
+ close(client->sock);
+
+ if (client->caps) {
+ g_slist_foreach(client->caps, (GFunc) g_free, NULL);
+ g_slist_free(client->caps);
+ }
+
+ g_free(client->interface);
+ g_free(client);
+}
+
+/* Pass file descriptor through local domain sockets (AF_LOCAL, formerly
+ * AF_UNIX) and the sendmsg() system call with the cmsg_type field of a "struct
+ * cmsghdr" set to SCM_RIGHTS and the data being an integer value equal to the
+ * handle of the file descriptor to be passed. */
+static int unix_sendmsg_fd(int sock, int fd)
+{
+ char cmsg_b[CMSG_SPACE(sizeof(int))], m = 'm';
+ struct cmsghdr *cmsg;
+ struct iovec iov = { &m, sizeof(m) };
+ struct msghdr msgh;
+
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = &cmsg_b;
+ msgh.msg_controllen = CMSG_LEN(sizeof(int));
+
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ /* Initialize the payload */
+ (*(int *) CMSG_DATA(cmsg)) = fd;
+
+ return sendmsg(sock, &msgh, MSG_NOSIGNAL);
+}
+
+static void unix_ipc_sendmsg(struct unix_client *client,
+ const bt_audio_msg_header_t *msg)
+{
+ info("Audio API: sending %s", bt_audio_strmsg(msg->msg_type));
+
+ if (send(client->sock, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) < 0)
+ error("Error %s(%d)", strerror(errno), errno);
+}
+
+static void unix_ipc_error(struct unix_client *client, int type, int err)
+{
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ bt_audio_rsp_msg_header_t *rsp_hdr = (void *) buf;
+
+ if (!g_slist_find(clients, client))
+ return;
+
+ memset(buf, 0, sizeof(buf));
+ rsp_hdr->msg_h.msg_type = type;
+ rsp_hdr->posix_errno = err;
+
+ unix_ipc_sendmsg(client, &rsp_hdr->msg_h);
+}
+
+static service_type_t select_service(struct audio_device *dev, const char *interface)
+{
+ if (!interface) {
+ if (dev->sink && avdtp_is_connected(&dev->src, &dev->dst))
+ return TYPE_SINK;
+ else if (dev->headset && headset_is_active(dev))
+ return TYPE_HEADSET;
+ else if (dev->sink)
+ return TYPE_SINK;
+ else if (dev->headset)
+ return TYPE_HEADSET;
+ } else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink)
+ return TYPE_SINK;
+ else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset)
+ return TYPE_HEADSET;
+
+ return TYPE_NONE;
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+ avdtp_state_t old_state,
+ avdtp_state_t new_state,
+ struct avdtp_error *err,
+ void *user_data)
+{
+ struct unix_client *client = user_data;
+ struct a2dp_data *a2dp = &client->d.a2dp;
+
+ switch (new_state) {
+ case AVDTP_STATE_IDLE:
+ if (a2dp->sep) {
+ a2dp_sep_unlock(a2dp->sep, a2dp->session);
+ a2dp->sep = NULL;
+ }
+ client->dev = NULL;
+ if (a2dp->session) {
+ avdtp_unref(a2dp->session);
+ a2dp->session = NULL;
+ }
+ a2dp->stream = NULL;
+ client->cb_id = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+static void headset_discovery_complete(struct audio_device *dev, void *user_data)
+{
+ struct unix_client *client = user_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_getcapabilities_rsp *rsp = (void *) buf;
+
+ client->req_id = 0;
+
+ if (!dev)
+ goto failed;
+
+ memset(buf, 0, sizeof(buf));
+
+ rsp->rsp_h.msg_h.msg_type = BT_GETCAPABILITIES_RSP;
+ rsp->transport = BT_CAPABILITIES_TRANSPORT_SCO;
+ rsp->sampling_rate = 8000;
+
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+
+ return;
+
+failed:
+ error("discovery failed");
+ unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+ client->dev = NULL;
+}
+
+static void headset_setup_complete(struct audio_device *dev, void *user_data)
+{
+ struct unix_client *client = user_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_setconfiguration_rsp *rsp = (void *) buf;
+ struct headset_data *hs = &client->d.hs;
+
+ client->req_id = 0;
+
+ if (!dev)
+ goto failed;
+
+ switch (client->access_mode) {
+ case BT_CAPABILITIES_ACCESS_MODE_READ:
+ hs->lock = HEADSET_LOCK_READ;
+ break;
+ case BT_CAPABILITIES_ACCESS_MODE_WRITE:
+ hs->lock = HEADSET_LOCK_WRITE;
+ break;
+ case BT_CAPABILITIES_ACCESS_MODE_READWRITE:
+ hs->lock = HEADSET_LOCK_READ | HEADSET_LOCK_WRITE;
+ break;
+ default:
+ hs->lock = 0;
+ break;
+ }
+
+ if (!headset_lock(dev, hs->lock)) {
+ error("Unable to lock headset");
+ goto failed;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ rsp->rsp_h.msg_h.msg_type = BT_SETCONFIGURATION_RSP;
+ rsp->transport = BT_CAPABILITIES_TRANSPORT_SCO;
+ rsp->access_mode = client->access_mode;
+ rsp->link_mtu = 48;
+
+ client->data_fd = headset_get_sco_fd(dev);
+
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+
+ return;
+
+failed:
+ error("config failed");
+ unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+ client->dev = NULL;
+}
+
+static void headset_resume_complete(struct audio_device *dev, void *user_data)
+{
+ struct unix_client *client = user_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_streamstart_rsp *rsp = (void *) buf;
+ struct bt_streamfd_ind *ind = (void *) buf;
+
+ client->req_id = 0;
+
+ if (!dev)
+ goto failed;
+
+ memset(buf, 0, sizeof(buf));
+
+ rsp->rsp_h.msg_h.msg_type = BT_STREAMSTART_RSP;
+
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+
+ memset(buf, 0, sizeof(buf));
+ ind->h.msg_type = BT_STREAMFD_IND;
+ unix_ipc_sendmsg(client, &ind->h);
+
+ client->data_fd = headset_get_sco_fd(dev);
+
+ if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
+ error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ error("resume failed");
+ unix_ipc_error(client, BT_STREAMSTART_RSP, EIO);
+ client->dev = NULL;
+}
+
+static void a2dp_discovery_complete(struct avdtp *session, GSList *seps,
+ struct avdtp_error *err,
+ void *user_data)
+{
+ struct unix_client *client = user_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_getcapabilities_rsp *rsp = (void *) buf;
+ struct a2dp_data *a2dp = &client->d.a2dp;
+ struct sbc_codec_cap *sbc_cap = NULL;
+ struct mpeg_codec_cap *mpeg_cap = NULL;
+ GSList *l;
+
+ if (!g_slist_find(clients, client)) {
+ debug("Client disconnected during discovery");
+ return;
+ }
+
+ if (err)
+ goto failed;
+
+ memset(buf, 0, sizeof(buf));
+ client->req_id = 0;
+
+ rsp->rsp_h.msg_h.msg_type = BT_GETCAPABILITIES_RSP;
+ rsp->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
+
+ for (l = seps; l; l = g_slist_next(l)) {
+ struct avdtp_remote_sep *rsep = l->data;
+ struct avdtp_service_capability *cap;
+ struct avdtp_media_codec_capability *codec_cap;
+
+ cap = avdtp_get_codec(rsep);
+
+ if (cap->category != AVDTP_MEDIA_CODEC)
+ continue;
+
+ codec_cap = (void *) cap->data;
+
+ if (codec_cap->media_codec_type == A2DP_CODEC_SBC && !sbc_cap)
+ sbc_cap = (void *) codec_cap;
+
+ if (codec_cap->media_codec_type == A2DP_CODEC_MPEG12 && !mpeg_cap)
+ mpeg_cap = (void *) codec_cap;
+ }
+
+ /* endianess prevent direct cast */
+ if (sbc_cap) {
+ rsp->sbc_capabilities.channel_mode = sbc_cap->channel_mode;
+ rsp->sbc_capabilities.frequency = sbc_cap->frequency;
+ rsp->sbc_capabilities.allocation_method = sbc_cap->allocation_method;
+ rsp->sbc_capabilities.subbands = sbc_cap->subbands;
+ rsp->sbc_capabilities.block_length = sbc_cap->block_length;
+ rsp->sbc_capabilities.min_bitpool = sbc_cap->min_bitpool;
+ rsp->sbc_capabilities.max_bitpool = sbc_cap->max_bitpool;
+ }
+
+ if (mpeg_cap) {
+ rsp->mpeg_capabilities.channel_mode = mpeg_cap->channel_mode;
+ rsp->mpeg_capabilities.crc = mpeg_cap->crc;
+ rsp->mpeg_capabilities.layer = mpeg_cap->layer;
+ rsp->mpeg_capabilities.frequency = mpeg_cap->frequency;
+ rsp->mpeg_capabilities.mpf = mpeg_cap->mpf;
+ rsp->mpeg_capabilities.bitrate = mpeg_cap->bitrate;
+ }
+
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+
+ return;
+
+failed:
+ error("discovery failed");
+ unix_ipc_error(client, BT_GETCAPABILITIES_RSP, EIO);
+
+ avdtp_unref(a2dp->session);
+
+ a2dp->session = NULL;
+ a2dp->stream = NULL;
+}
+
+static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep,
+ struct avdtp_stream *stream,
+ struct avdtp_error *err,
+ void *user_data)
+{
+ struct unix_client *client = user_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_setconfiguration_rsp *rsp = (void *) buf;
+ struct a2dp_data *a2dp = &client->d.a2dp;
+ uint16_t imtu, omtu;
+ GSList *caps;
+
+ if (err)
+ goto failed;
+
+ memset(buf, 0, sizeof(buf));
+ client->req_id = 0;
+
+ if (!stream)
+ goto failed;
+
+ if (!a2dp_sep_lock(sep, session)) {
+ error("Unable to lock A2DP source SEP");
+ goto failed;
+ }
+
+ a2dp->sep = sep;
+ a2dp->stream = stream;
+
+ if (!avdtp_stream_get_transport(stream, &client->data_fd, &imtu, &omtu,
+ &caps)) {
+ error("Unable to get stream transport");
+ goto failed;
+ }
+
+ rsp->rsp_h.msg_h.msg_type = BT_SETCONFIGURATION_RSP;
+ rsp->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
+ client->access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE;
+ rsp->access_mode = client->access_mode;
+ /* FIXME: Use imtu when fd_opt is CFG_FD_OPT_READ */
+ rsp->link_mtu = omtu;
+
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+
+ client->cb_id = avdtp_stream_add_cb(session, stream,
+ stream_state_changed, client);
+
+ return;
+
+failed:
+ error("config failed");
+
+ if (a2dp->sep) {
+ a2dp_sep_unlock(a2dp->sep, a2dp->session);
+ a2dp->sep = NULL;
+ }
+ unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+
+ avdtp_unref(a2dp->session);
+
+ a2dp->session = NULL;
+ a2dp->stream = NULL;
+}
+
+static void a2dp_resume_complete(struct avdtp *session,
+ struct avdtp_error *err, void *user_data)
+{
+ struct unix_client *client = user_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_streamstart_rsp *rsp = (void *) buf;
+ struct bt_streamfd_ind *ind = (void *) buf;
+ struct a2dp_data *a2dp = &client->d.a2dp;
+
+ if (err)
+ goto failed;
+
+ memset(buf, 0, sizeof(buf));
+ rsp->rsp_h.msg_h.msg_type = BT_STREAMSTART_RSP;
+ rsp->rsp_h.posix_errno = 0;
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+
+ memset(buf, 0, sizeof(buf));
+ ind->h.msg_type = BT_STREAMFD_IND;
+ unix_ipc_sendmsg(client, &ind->h);
+
+ if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
+ error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ error("resume failed");
+
+ if (a2dp->sep) {
+ a2dp_sep_unlock(a2dp->sep, a2dp->session);
+ a2dp->sep = NULL;
+ }
+ unix_ipc_error(client, BT_STREAMSTART_RSP, EIO);
+
+ avdtp_unref(a2dp->session);
+
+ a2dp->session = NULL;
+ a2dp->stream = NULL;
+}
+
+static void a2dp_suspend_complete(struct avdtp *session,
+ struct avdtp_error *err, void *user_data)
+{
+ struct unix_client *client = user_data;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_streamstart_rsp *rsp = (void *) buf;
+ struct a2dp_data *a2dp = &client->d.a2dp;
+
+ if (err)
+ goto failed;
+
+ memset(buf, 0, sizeof(buf));
+ rsp->rsp_h.msg_h.msg_type = BT_STREAMSTOP_RSP;
+ rsp->rsp_h.posix_errno = 0;
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+
+ return;
+
+failed:
+ error("suspend failed");
+
+ if (a2dp->sep) {
+ a2dp_sep_unlock(a2dp->sep, a2dp->session);
+ a2dp->sep = NULL;
+ }
+ unix_ipc_error(client, BT_STREAMSTOP_RSP, EIO);
+
+ avdtp_unref(a2dp->session);
+
+ a2dp->session = NULL;
+ a2dp->stream = NULL;
+}
+
+static void start_discovery(struct audio_device *dev, struct unix_client *client)
+{
+ struct a2dp_data *a2dp;
+ int err = 0;
+
+ client->type = select_service(dev, client->interface);
+
+ switch (client->type) {
+ case TYPE_SINK:
+ a2dp = &client->d.a2dp;
+
+ if (!a2dp->session)
+ a2dp->session = avdtp_get(&dev->src, &dev->dst);
+
+ if (!a2dp->session) {
+ error("Unable to get a session");
+ goto failed;
+ }
+
+ err = avdtp_discover(a2dp->session, a2dp_discovery_complete,
+ client);
+ if (err)
+ goto failed;
+ break;
+
+ case TYPE_HEADSET:
+ headset_discovery_complete(dev, client);
+ break;
+
+ default:
+ error("No known services for device");
+ goto failed;
+ }
+
+ client->dev = dev;
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_GETCAPABILITIES_RSP, err ? : EIO);
+}
+
+static void start_config(struct audio_device *dev, struct unix_client *client)
+{
+ struct a2dp_data *a2dp;
+ unsigned int id;
+
+ client->type = select_service(dev, client->interface);
+
+ switch (client->type) {
+ case TYPE_SINK:
+ a2dp = &client->d.a2dp;
+
+ if (!a2dp->session)
+ a2dp->session = avdtp_get(&dev->src, &dev->dst);
+
+ if (!a2dp->session) {
+ error("Unable to get a session");
+ goto failed;
+ }
+
+ id = a2dp_source_config(a2dp->session, a2dp_config_complete,
+ client->caps, client);
+ client->cancel = a2dp_source_cancel;
+ break;
+
+ case TYPE_HEADSET:
+ id = headset_request_stream(dev, headset_setup_complete, client);
+ client->cancel = headset_cancel_stream;
+ break;
+
+ default:
+ error("No known services for device");
+ goto failed;
+ }
+
+ if (id == 0) {
+ error("config failed");
+ goto failed;
+ }
+
+ client->req_id = id;
+ client->dev = dev;
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+}
+
+static void start_resume(struct audio_device *dev, struct unix_client *client)
+{
+ struct a2dp_data *a2dp;
+ unsigned int id;
+
+ client->type = select_service(dev, client->interface);
+
+ switch (client->type) {
+ case TYPE_SINK:
+ a2dp = &client->d.a2dp;
+
+ if (!a2dp->session)
+ a2dp->session = avdtp_get(&dev->src, &dev->dst);
+
+ if (!a2dp->session) {
+ error("Unable to get a session");
+ goto failed;
+ }
+
+ if (!a2dp->sep) {
+ error("Unable to get a sep");
+ goto failed;
+ }
+
+ id = a2dp_source_resume(a2dp->session, a2dp->sep,
+ a2dp_resume_complete, client);
+ client->cancel = a2dp_source_cancel;
+
+ if (id == 0) {
+ error("resume failed");
+ goto failed;
+ }
+
+ break;
+
+ case TYPE_HEADSET:
+ headset_resume_complete(dev, client);
+ break;
+
+ default:
+ error("No known services for device");
+ goto failed;
+ }
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_STREAMSTART_RSP, EIO);
+}
+
+static void start_suspend(struct audio_device *dev, struct unix_client *client)
+{
+ struct a2dp_data *a2dp;
+ unsigned int id;
+
+ client->type = select_service(dev, client->interface);
+
+ switch (client->type) {
+ case TYPE_SINK:
+ a2dp = &client->d.a2dp;
+
+ if (!a2dp->session)
+ a2dp->session = avdtp_get(&dev->src, &dev->dst);
+
+ if (!a2dp->session) {
+ error("Unable to get a session");
+ goto failed;
+ }
+
+ if (!a2dp->sep) {
+ error("Unable to get a sep");
+ goto failed;
+ }
+
+ id = a2dp_source_suspend(a2dp->session, a2dp->sep,
+ a2dp_suspend_complete, client);
+ client->cancel = a2dp_source_cancel;
+ break;
+
+ case TYPE_HEADSET:
+ id = headset_request_stream(dev, headset_setup_complete, client);
+ client->cancel = headset_cancel_stream;
+ break;
+
+ default:
+ error("No known services for device");
+ goto failed;
+ }
+
+ if (id == 0) {
+ error("suspend failed");
+ goto failed;
+ }
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_STREAMSTOP_RSP, EIO);
+}
+
+static void create_cb(struct audio_device *dev, void *user_data)
+{
+ struct unix_client *client = user_data;
+
+ if (!dev)
+ unix_ipc_error(client, BT_GETCAPABILITIES_RSP, EIO);
+ else
+ start_discovery(dev, client);
+}
+
+static void handle_getcapabilities_req(struct unix_client *client,
+ struct bt_getcapabilities_req *req)
+{
+ struct audio_device *dev;
+ bdaddr_t bdaddr;
+
+ str2ba(req->device, &bdaddr);
+
+ if (client->interface) {
+ g_free(client->interface);
+ client->interface = NULL;
+ }
+
+ 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(&bdaddr, NULL, FALSE)) {
+ if (!(req->flags & BT_FLAG_AUTOCONNECT))
+ goto failed;
+ if (!bacmp(&bdaddr, BDADDR_ANY))
+ goto failed;
+ if (!manager_create_device(&bdaddr, create_cb, client))
+ goto failed;
+ return;
+ }
+
+ dev = manager_find_device(&bdaddr, client->interface, TRUE);
+ if (!dev) {
+ if (req->flags & BT_FLAG_AUTOCONNECT)
+ dev = manager_find_device(&bdaddr, client->interface, FALSE);
+ else
+ goto failed;
+ }
+
+ if (!dev)
+ goto failed;
+
+ start_discovery(dev, client);
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_GETCAPABILITIES_RSP, EIO);
+}
+
+static int handle_sco_transport(struct unix_client *client,
+ struct bt_setconfiguration_req *req)
+{
+ client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
+
+ info("config sco - device = %s access_mode = %u", req->device,
+ req->access_mode);
+
+ return 0;
+}
+
+static int handle_a2dp_transport(struct unix_client *client,
+ struct bt_setconfiguration_req *req)
+{
+ struct avdtp_service_capability *media_transport, *media_codec;
+ struct sbc_codec_cap sbc_cap;
+ struct mpeg_codec_cap mpeg_cap;
+
+ client->interface = g_strdup(AUDIO_SINK_INTERFACE);
+
+ if (client->caps) {
+ g_slist_foreach(client->caps, (GFunc) g_free, NULL);
+ g_slist_free(client->caps);
+ }
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ client->caps = g_slist_append(client->caps, media_transport);
+
+ info("config a2dp - device = %s access_mode = %u", req->device,
+ req->access_mode);
+
+ if (req->mpeg_capabilities.frequency) {
+
+ memset(&mpeg_cap, 0, sizeof(mpeg_cap));
+
+ mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
+ mpeg_cap.channel_mode = req->mpeg_capabilities.channel_mode;
+ mpeg_cap.crc = req->mpeg_capabilities.crc;
+ mpeg_cap.layer = req->mpeg_capabilities.layer;
+ mpeg_cap.frequency = req->mpeg_capabilities.frequency;
+ mpeg_cap.mpf = req->mpeg_capabilities.mpf;
+ mpeg_cap.bitrate = req->mpeg_capabilities.bitrate;
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
+ sizeof(mpeg_cap));
+
+ info("codec mpeg12 - frequency = %u channel_mode = %u "
+ "layer = %u crc = %u mpf = %u bitrate = %u",
+ mpeg_cap.frequency, mpeg_cap.channel_mode,
+ mpeg_cap.layer, mpeg_cap.crc, mpeg_cap.mpf,
+ mpeg_cap.bitrate);
+ } else if (req->sbc_capabilities.frequency) {
+ memset(&sbc_cap, 0, sizeof(sbc_cap));
+
+ sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
+ sbc_cap.channel_mode = req->sbc_capabilities.channel_mode;
+ sbc_cap.frequency = req->sbc_capabilities.frequency;
+ sbc_cap.allocation_method = req->sbc_capabilities.allocation_method;
+ sbc_cap.subbands = req->sbc_capabilities.subbands;
+ sbc_cap.block_length = req->sbc_capabilities.block_length;
+ sbc_cap.min_bitpool = req->sbc_capabilities.min_bitpool;
+ sbc_cap.max_bitpool = req->sbc_capabilities.max_bitpool;
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
+ sizeof(sbc_cap));
+
+ info("codec sbc - frequency = %u channel_mode = %u "
+ "allocation = %u subbands = %u blocks = %u "
+ "bitpool = %u", sbc_cap.frequency,
+ sbc_cap.channel_mode, sbc_cap.allocation_method,
+ sbc_cap.subbands, sbc_cap.block_length,
+ sbc_cap.max_bitpool);
+ } else
+ return -EINVAL;
+
+ client->caps = g_slist_append(client->caps, media_codec);
+
+ return 0;
+}
+
+static void handle_setconfiguration_req(struct unix_client *client,
+ struct bt_setconfiguration_req *req)
+{
+ struct audio_device *dev;
+ bdaddr_t bdaddr;
+ int err = 0;
+
+ if (!req->access_mode) {
+ err = EINVAL;
+ goto failed;
+ }
+
+ str2ba(req->device, &bdaddr);
+
+ if (client->interface) {
+ g_free(client->interface);
+ client->interface = NULL;
+ }
+
+ if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO) {
+ err = handle_sco_transport(client, req);
+ if (err < 0) {
+ err = -err;
+ goto failed;
+ }
+ } else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
+ err = handle_a2dp_transport(client, req);
+ if (err < 0) {
+ err = -err;
+ goto failed;
+ }
+ }
+
+ if (!manager_find_device(&bdaddr, NULL, FALSE)) {
+ if (!bacmp(&bdaddr, BDADDR_ANY))
+ goto failed;
+ if (!manager_create_device(&bdaddr, create_cb, client))
+ goto failed;
+ return;
+ }
+
+ dev = manager_find_device(&bdaddr, client->interface, TRUE);
+ if (!dev)
+ dev = manager_find_device(&bdaddr, client->interface, FALSE);
+
+ if (!dev)
+ goto failed;
+
+ client->access_mode = req->access_mode;
+
+ start_config(dev, client);
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_SETCONFIGURATION_RSP, err ? : EIO);
+}
+
+static void handle_streamstart_req(struct unix_client *client,
+ struct bt_streamstart_req *req)
+{
+ if (!client->dev)
+ goto failed;
+
+ start_resume(client->dev, client);
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_STREAMSTART_REQ, EIO);
+}
+
+static void handle_streamstop_req(struct unix_client *client,
+ struct bt_streamstop_req *req)
+{
+ if (!client->dev)
+ goto failed;
+
+ start_suspend(client->dev, client);
+
+ return;
+
+failed:
+ unix_ipc_error(client, BT_STREAMSTOP_REQ, EIO);
+}
+
+static void handle_control_req(struct unix_client *client,
+ struct bt_control_req *req)
+{
+ /* FIXME: really implement that */
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_setconfiguration_rsp *rsp = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+ rsp->rsp_h.msg_h.msg_type = BT_CONTROL_RSP;
+ rsp->rsp_h.posix_errno = 0;
+
+ unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+}
+
+static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ bt_audio_msg_header_t *msghdr = (void *) buf;
+ struct unix_client *client = data;
+ int len;
+ struct a2dp_data *a2dp = &client->d.a2dp;
+ struct headset_data *hs = &client->d.hs;
+ const char *type;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ debug("Unix client disconnected (fd=%d)", client->sock);
+ switch (client->type) {
+ case TYPE_HEADSET:
+ if (client->dev)
+ headset_unlock(client->dev, hs->lock);
+ break;
+ case TYPE_SOURCE:
+ case TYPE_SINK:
+ if (a2dp->sep) {
+ a2dp_sep_unlock(a2dp->sep, a2dp->session);
+ a2dp->sep = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (client->cancel && client->req_id > 0)
+ client->cancel(client->dev, client->req_id);
+ goto failed;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ len = recv(client->sock, buf, sizeof(buf), MSG_WAITALL);
+ if (len < 0) {
+ error("recv: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ if ((type = bt_audio_strmsg(msghdr->msg_type)))
+ info("Audio API: received %s", type);
+
+ switch (msghdr->msg_type) {
+ case BT_GETCAPABILITIES_REQ:
+ handle_getcapabilities_req(client,
+ (struct bt_getcapabilities_req *) msghdr);
+ break;
+ case BT_SETCONFIGURATION_REQ:
+ handle_setconfiguration_req(client,
+ (struct bt_setconfiguration_req *) msghdr);
+ break;
+ case BT_STREAMSTART_REQ:
+ handle_streamstart_req(client,
+ (struct bt_streamstart_req *) msghdr);
+ break;
+ case BT_STREAMSTOP_REQ:
+ handle_streamstop_req(client,
+ (struct bt_streamstop_req *) msghdr);
+ break;
+ case BT_CONTROL_REQ:
+ handle_control_req(client,
+ (struct bt_control_req *) msghdr);
+ break;
+ default:
+ error("Audio API: received unexpected packet type %d",
+ msghdr->msg_type);
+ }
+
+ return TRUE;
+
+failed:
+ clients = g_slist_remove(clients, client);
+ client_free(client);
+ return FALSE;
+}
+
+static gboolean server_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ int sk, cli_sk;
+ struct unix_client *client;
+ GIOChannel *io;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_close(chan);
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+
+ cli_sk = accept(sk, (struct sockaddr *) &addr, &addrlen);
+ if (cli_sk < 0) {
+ error("accept: %s (%d)", strerror(errno), errno);
+ return TRUE;
+ }
+
+ debug("Accepted new client connection on unix socket (fd=%d)", cli_sk);
+
+ client = g_new0(struct unix_client, 1);
+ client->sock = cli_sk;
+ clients = g_slist_append(clients, client);
+
+ io = g_io_channel_unix_new(cli_sk);
+ g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ client_cb, client);
+ g_io_channel_unref(io);
+
+ return TRUE;
+}
+
+int unix_init(void)
+{
+ GIOChannel *io;
+ struct sockaddr_un addr = {
+ AF_UNIX, BT_IPC_SOCKET_NAME
+ };
+
+ int sk, err;
+
+ sk = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = errno;
+ error("Can't create unix socket: %s (%d)", strerror(err), err);
+ return -err;
+ }
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ error("Can't bind unix socket: %s (%d)", strerror(errno),
+ errno);
+ close(sk);
+ return -1;
+ }
+
+ set_nonblocking(sk);
+
+ unix_sock = sk;
+
+ listen(sk, 1);
+
+ io = g_io_channel_unix_new(sk);
+ g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ server_cb, NULL);
+ g_io_channel_unref(io);
+
+ info("Unix socket created: %d", sk);
+
+ return 0;
+}
+
+void unix_exit(void)
+{
+ g_slist_foreach(clients, (GFunc) client_free, NULL);
+ g_slist_free(clients);
+ close(unix_sock);
+ unix_sock = -1;
+}
diff --git a/utils/audio/unix.h b/utils/audio/unix.h
new file mode 100644
index 00000000..62474509
--- /dev/null
+++ b/utils/audio/unix.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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 unix_init(void);
+void unix_exit(void);
diff --git a/utils/common/Makefile.am b/utils/common/Makefile.am
new file mode 100644
index 00000000..6ae5ed7a
--- /dev/null
+++ b/utils/common/Makefile.am
@@ -0,0 +1,16 @@
+
+noinst_LIBRARIES = libhelper.a
+
+libhelper_a_SOURCES = oui.h oui.c textfile.h textfile.c \
+ logging.h logging.c error.h error.c \
+ glib-helper.h glib-helper.c sdp-xml.h sdp-xml.c sdp-glib.c
+
+noinst_PROGRAMS = test_textfile
+
+test_textfile_LDADD = libhelper.a
+
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+EXTRA_DIST = ppoll.h uinput.h
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/common/Makefile.in b/utils/common/Makefile.in
new file mode 100644
index 00000000..fc3d1aed
--- /dev/null
+++ b/utils/common/Makefile.in
@@ -0,0 +1,485 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = test_textfile$(EXEEXT)
+subdir = common
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libhelper_a_AR = $(AR) $(ARFLAGS)
+libhelper_a_LIBADD =
+am_libhelper_a_OBJECTS = oui.$(OBJEXT) textfile.$(OBJEXT) \
+ logging.$(OBJEXT) error.$(OBJEXT) glib-helper.$(OBJEXT) \
+ sdp-xml.$(OBJEXT) sdp-glib.$(OBJEXT)
+libhelper_a_OBJECTS = $(am_libhelper_a_OBJECTS)
+PROGRAMS = $(noinst_PROGRAMS)
+test_textfile_SOURCES = test_textfile.c
+test_textfile_OBJECTS = test_textfile.$(OBJEXT)
+test_textfile_DEPENDENCIES = libhelper.a
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libhelper_a_SOURCES) test_textfile.c
+DIST_SOURCES = $(libhelper_a_SOURCES) test_textfile.c
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LIBRARIES = libhelper.a
+libhelper_a_SOURCES = oui.h oui.c textfile.h textfile.c \
+ logging.h logging.c error.h error.c \
+ glib-helper.h glib-helper.c sdp-xml.h sdp-xml.c sdp-glib.c
+
+test_textfile_LDADD = libhelper.a
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+EXTRA_DIST = ppoll.h uinput.h
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu common/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu common/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libhelper.a: $(libhelper_a_OBJECTS) $(libhelper_a_DEPENDENCIES)
+ -rm -f libhelper.a
+ $(libhelper_a_AR) libhelper.a $(libhelper_a_OBJECTS) $(libhelper_a_LIBADD)
+ $(RANLIB) libhelper.a
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+test_textfile$(EXEEXT): $(test_textfile_OBJECTS) $(test_textfile_DEPENDENCIES)
+ @rm -f test_textfile$(EXEEXT)
+ $(LINK) $(test_textfile_OBJECTS) $(test_textfile_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glib-helper.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oui.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdp-glib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdp-xml.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_textfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/textfile.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES clean-noinstPROGRAMS ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/common/error.c b/utils/common/error.c
new file mode 100644
index 00000000..bc813d74
--- /dev/null
+++ b/utils/common/error.c
@@ -0,0 +1,126 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2007-2008 Fabien Chevalier <fabchevalier@free.fr>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <gdbus.h>
+
+#include "error.h"
+
+DBusMessage *create_errno_message(DBusMessage *msg, int err)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ strerror(err));
+}
+
+/**
+ org.bluez.Error.ConnectionAttemptFailed:
+
+ An unexpected error (other than DeviceUnreachable) error has occured while
+ attempting a connection to a device
+*/
+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");
+}
+
+/**
+ org.bluez.Error.NotSupported:
+
+ The remote device does not support the expected feature.
+ Examples of use: trying to connect to audio device while audio is not
+ declared in device sdp record.
+*/
+DBusHandlerResult error_not_supported(DBusConnection *conn, DBusMessage *msg)
+{
+ return error_common_reply(conn, msg, ERROR_INTERFACE ".NotSupported",
+ "Not supported");
+}
+
+/**
+ org.bluez.Error.Canceled:
+
+ The operation was canceled.
+ Examples of use : autorization process canceled, connection canceled
+*/
+DBusHandlerResult error_canceled(DBusConnection *conn, DBusMessage *msg,
+ const char *str)
+{
+ return error_common_reply(conn, msg, ERROR_INTERFACE ".Canceled", str);
+}
+
+/**
+ org.bluez.Error.Failed:
+
+ This is a the most generic error.
+ desc filed is MANDATORY
+*/
+DBusHandlerResult error_failed(DBusConnection *conn, DBusMessage *msg,
+ const char * desc)
+{
+ return error_common_reply(conn, msg, ERROR_INTERFACE ".Failed", desc);
+}
+
+/**
+ org.bluez.Error.Failed:
+
+ This is a the most generic error, instantiated form a UNIX errno number.
+*/
+DBusHandlerResult error_failed_errno(DBusConnection *conn, DBusMessage *msg,
+ int err)
+{
+ const char *desc = strerror(err);
+
+ return error_failed(conn, msg, desc);
+}
+
+/* Helper function - internal use only */
+DBusHandlerResult error_common_reply(DBusConnection *conn, DBusMessage *msg,
+ const char *name, const char *descr)
+{
+ DBusMessage *derr;
+ dbus_bool_t ret;
+
+ if (!conn || !msg)
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ derr = dbus_message_new_error(msg, name, descr);
+ if (!derr)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ ret = dbus_connection_send(conn, derr, NULL);
+
+ dbus_message_unref(derr);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
diff --git a/utils/common/error.h b/utils/common/error.h
new file mode 100644
index 00000000..68ce105a
--- /dev/null
+++ b/utils/common/error.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2007-2008 Fabien Chevalier <fabchevalier@free.fr>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <dbus/dbus.h>
+
+#define ERROR_INTERFACE "org.bluez.Error"
+
+DBusMessage *create_errno_message(DBusMessage *msg, int err);
+
+DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn,
+ DBusMessage *msg,
+ int err);
+
+DBusHandlerResult error_not_supported(DBusConnection *conn,
+ DBusMessage *msg);
+
+DBusHandlerResult error_canceled(DBusConnection *conn, DBusMessage *msg,
+ const char *str);
+
+DBusHandlerResult error_failed(DBusConnection *conn, DBusMessage *msg,
+ const char *desc);
+
+DBusHandlerResult error_failed_errno(DBusConnection *conn, DBusMessage *msg,
+ int err);
+
+DBusHandlerResult error_common_reply(DBusConnection *conn, DBusMessage *msg,
+ const char *name, const char *descr);
diff --git a/utils/common/glib-helper.c b/utils/common/glib-helper.c
new file mode 100644
index 00000000..f0435aca
--- /dev/null
+++ b/utils/common/glib-helper.c
@@ -0,0 +1,1283 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "glib-helper.h"
+
+typedef int (*resolver_t) (int fd, char *src, char *dst);
+typedef BtIOError (*connect_t) (BtIO *io, BtIOFunc func);
+typedef BtIOError (*listen_t) (BtIO *io, BtIOFunc func);
+
+int set_nonblocking(int fd)
+{
+ long arg;
+
+ arg = fcntl(fd, F_GETFL);
+ if (arg < 0)
+ return -errno;
+
+ /* Return if already nonblocking */
+ if (arg & O_NONBLOCK)
+ return 0;
+
+ arg |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, arg) < 0)
+ return -errno;
+
+ return 0;
+}
+
+struct io_context {
+ int fd;
+ GIOChannel *io;
+ BtIOFunc func;
+ bt_io_callback_t cb;
+ resolver_t resolver;
+ gpointer user_data;
+};
+
+struct bt_io {
+ char src[18];
+ char dst[18];
+ guint32 flags;
+ guint8 channel;
+ guint16 psm;
+ guint16 mtu;
+ BtIOTransport type;
+ connect_t connect;
+ listen_t listen;
+ struct io_context *io_ctxt;
+ int refcount;
+};
+
+struct search_context {
+ bdaddr_t src;
+ bdaddr_t dst;
+ sdp_session_t *session;
+ bt_callback_t cb;
+ bt_destroy_t destroy;
+ gpointer user_data;
+ uuid_t uuid;
+};
+
+static GSList *context_list = NULL;
+
+static void search_context_cleanup(struct search_context *ctxt)
+{
+ context_list = g_slist_remove(context_list, ctxt);
+
+ if (ctxt->destroy)
+ ctxt->destroy(ctxt->user_data);
+
+ g_free(ctxt);
+}
+
+static void search_completed_cb(uint8_t type, uint16_t status,
+ uint8_t *rsp, size_t size, void *user_data)
+{
+ struct search_context *ctxt = user_data;
+ sdp_list_t *recs = NULL;
+ int scanned, seqlen = 0, bytesleft = size;
+ uint8_t dataType;
+ int err = 0;
+
+ if (status || type != SDP_SVC_SEARCH_ATTR_RSP) {
+ err = -EPROTO;
+ goto done;
+ }
+
+ scanned = sdp_extract_seqtype_safe(rsp, bytesleft, &dataType, &seqlen);
+ if (!scanned || !seqlen)
+ goto done;
+
+ rsp += scanned;
+ bytesleft -= scanned;
+ do {
+ sdp_record_t *rec;
+ int recsize;
+
+ recsize = 0;
+ rec = sdp_extract_pdu_safe(rsp, bytesleft, &recsize);
+ if (!rec)
+ break;
+
+ if (!recsize) {
+ sdp_record_free(rec);
+ break;
+ }
+
+ scanned += recsize;
+ rsp += recsize;
+ bytesleft -= recsize;
+
+ recs = sdp_list_append(recs, rec);
+ } while (scanned < size && bytesleft > 0);
+
+done:
+ sdp_close(ctxt->session);
+
+ if (ctxt->cb)
+ ctxt->cb(recs, err, ctxt->user_data);
+
+ search_context_cleanup(ctxt);
+}
+
+static gboolean search_process_cb(GIOChannel *chan,
+ GIOCondition cond, void *user_data)
+{
+ struct search_context *ctxt = user_data;
+ int err = 0;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ err = EIO;
+ goto failed;
+ }
+
+ if (sdp_process(ctxt->session) < 0)
+ goto failed;
+
+ return TRUE;
+
+failed:
+ if (err) {
+ sdp_close(ctxt->session);
+
+ if (ctxt->cb)
+ ctxt->cb(NULL, err, ctxt->user_data);
+
+ search_context_cleanup(ctxt);
+ }
+
+ return FALSE;
+}
+
+static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+{
+ struct search_context *ctxt = user_data;
+ sdp_list_t *search, *attrids;
+ uint32_t range = 0x0000ffff;
+ socklen_t len;
+ int sk, err = 0;
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ len = sizeof(err);
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
+ err = errno;
+ goto failed;
+ }
+
+ if (err != 0)
+ goto failed;
+
+ if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
+ err = EIO;
+ goto failed;
+ }
+
+ search = sdp_list_append(NULL, &ctxt->uuid);
+ attrids = sdp_list_append(NULL, &range);
+ if (sdp_service_search_attr_async(ctxt->session,
+ search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
+ sdp_list_free(attrids, NULL);
+ sdp_list_free(search, NULL);
+ err = EIO;
+ goto failed;
+ }
+
+ sdp_list_free(attrids, NULL);
+ sdp_list_free(search, NULL);
+
+ /* Set callback responsible for update the internal SDP transaction */
+ g_io_add_watch(chan, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ search_process_cb, ctxt);
+ return FALSE;
+
+failed:
+ sdp_close(ctxt->session);
+
+ if (ctxt->cb)
+ ctxt->cb(NULL, -err, ctxt->user_data);
+
+ search_context_cleanup(ctxt);
+
+ return FALSE;
+}
+
+static int create_search_context(struct search_context **ctxt,
+ const bdaddr_t *src, const bdaddr_t *dst,
+ uuid_t *uuid)
+{
+ sdp_session_t *s;
+ GIOChannel *chan;
+
+ if (!ctxt)
+ return -EINVAL;
+
+ s = sdp_connect(src, dst, SDP_NON_BLOCKING);
+ if (!s)
+ return -errno;
+
+ *ctxt = g_try_malloc0(sizeof(struct search_context));
+ if (!*ctxt) {
+ sdp_close(s);
+ return -ENOMEM;
+ }
+
+ bacpy(&(*ctxt)->src, src);
+ bacpy(&(*ctxt)->dst, dst);
+ (*ctxt)->session = s;
+ (*ctxt)->uuid = *uuid;
+
+ chan = g_io_channel_unix_new(sdp_get_socket(s));
+ g_io_add_watch(chan, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ connect_watch, *ctxt);
+ g_io_channel_unref(chan);
+
+ return 0;
+}
+
+int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
+ uuid_t *uuid, bt_callback_t cb, void *user_data,
+ bt_destroy_t destroy)
+{
+ struct search_context *ctxt = NULL;
+ int err;
+
+ if (!cb)
+ return -EINVAL;
+
+ err = create_search_context(&ctxt, src, dst, uuid);
+ if (err < 0)
+ return err;
+
+ ctxt->cb = cb;
+ ctxt->destroy = destroy;
+ ctxt->user_data = user_data;
+
+ context_list = g_slist_append(context_list, ctxt);
+
+ return 0;
+}
+
+int bt_discover_services(const bdaddr_t *src, const bdaddr_t *dst,
+ bt_callback_t cb, void *user_data, bt_destroy_t destroy)
+{
+ uuid_t uuid;
+
+ sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
+
+ return bt_search_service(src, dst, &uuid, cb, user_data, destroy);
+}
+
+static int find_by_bdaddr(const void *data, const void *user_data)
+{
+ const struct search_context *ctxt = data, *search = user_data;
+
+ return (bacmp(&ctxt->dst, &search->dst) &&
+ bacmp(&ctxt->src, &search->src));
+}
+
+int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct search_context search, *ctxt;
+ GSList *match;
+
+ memset(&search, 0, sizeof(search));
+ bacpy(&search.src, src);
+ bacpy(&search.dst, dst);
+
+ /* Ongoing SDP Discovery */
+ match = g_slist_find_custom(context_list, &search, find_by_bdaddr);
+ if (!match)
+ return -ENODATA;
+
+ ctxt = match->data;
+ if (!ctxt->session)
+ return -ENOTCONN;
+
+ close(ctxt->session->sock);
+ return 0;
+}
+
+char *bt_uuid2string(uuid_t *uuid)
+{
+ gchar *str;
+ uuid_t uuid128;
+ unsigned int data0;
+ unsigned short data1;
+ unsigned short data2;
+ unsigned short data3;
+ unsigned int data4;
+ unsigned short data5;
+
+ if (!uuid)
+ return NULL;
+
+ switch (uuid->type) {
+ case SDP_UUID16:
+ sdp_uuid16_to_uuid128(&uuid128, uuid);
+ break;
+ case SDP_UUID32:
+ sdp_uuid32_to_uuid128(&uuid128, uuid);
+ break;
+ case SDP_UUID128:
+ memcpy(&uuid128, uuid, sizeof(uuid_t));
+ break;
+ default:
+ /* Type of UUID unknown */
+ return NULL;
+ }
+
+ memcpy(&data0, &uuid128.value.uuid128.data[0], 4);
+ memcpy(&data1, &uuid128.value.uuid128.data[4], 2);
+ memcpy(&data2, &uuid128.value.uuid128.data[6], 2);
+ memcpy(&data3, &uuid128.value.uuid128.data[8], 2);
+ memcpy(&data4, &uuid128.value.uuid128.data[10], 4);
+ memcpy(&data5, &uuid128.value.uuid128.data[14], 2);
+
+ str = g_try_malloc0(MAX_LEN_UUID_STR);
+ if (!str)
+ return NULL;
+
+ sprintf(str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+ g_ntohl(data0), g_ntohs(data1),
+ g_ntohs(data2), g_ntohs(data3),
+ g_ntohl(data4), g_ntohs(data5));
+
+ return str;
+}
+
+static struct {
+ const char *name;
+ uint16_t class;
+} bt_services[] = {
+ { "vcp", VIDEO_CONF_SVCLASS_ID },
+ { "pbap", PBAP_SVCLASS_ID },
+ { "sap", SAP_SVCLASS_ID },
+ { "ftp", OBEX_FILETRANS_SVCLASS_ID },
+ { "bpp", BASIC_PRINTING_SVCLASS_ID },
+ { "bip", IMAGING_SVCLASS_ID },
+ { "synch", IRMC_SYNC_SVCLASS_ID },
+ { "dun", DIALUP_NET_SVCLASS_ID },
+ { "opp", OBEX_OBJPUSH_SVCLASS_ID },
+ { "fax", FAX_SVCLASS_ID },
+ { "spp", SERIAL_PORT_SVCLASS_ID },
+ { "hsp", HEADSET_SVCLASS_ID },
+ { "hfp", HANDSFREE_SVCLASS_ID },
+ { }
+};
+
+uint16_t bt_string2class(const char *pattern)
+{
+ int i;
+
+ for (i = 0; bt_services[i].name; i++) {
+ if (strcasecmp(bt_services[i].name, pattern) == 0)
+ return bt_services[i].class;
+ }
+
+ return 0;
+}
+
+int bt_string2uuid(uuid_t *uuid, const char *string)
+{
+ uint32_t data0, data4;
+ uint16_t data1, data2, data3, data5;
+
+ if (strlen(string) == 36 &&
+ string[8] == '-' &&
+ string[13] == '-' &&
+ string[18] == '-' &&
+ string[23] == '-' &&
+ sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
+ &data0, &data1, &data2, &data3, &data4, &data5) == 6) {
+ uint8_t val[16];
+
+ data0 = g_htonl(data0);
+ data1 = g_htons(data1);
+ data2 = g_htons(data2);
+ data3 = g_htons(data3);
+ data4 = g_htonl(data4);
+ data5 = g_htons(data5);
+
+ memcpy(&val[0], &data0, 4);
+ memcpy(&val[4], &data1, 2);
+ memcpy(&val[6], &data2, 2);
+ memcpy(&val[8], &data3, 2);
+ memcpy(&val[10], &data4, 4);
+ memcpy(&val[14], &data5, 2);
+
+ sdp_uuid128_create(uuid, val);
+
+ return 0;
+ } else {
+ uint16_t class = bt_string2class(string);
+ if (class) {
+ sdp_uuid16_create(uuid, class);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+gchar *bt_list2string(GSList *list)
+{
+ GSList *l;
+ gchar *str, *tmp;
+
+ if (!list)
+ return NULL;
+
+ str = g_strdup((const gchar *) list->data);
+
+ for (l = list->next; l; l = l->next) {
+ tmp = g_strconcat(str, " " , (const gchar *) l->data, NULL);
+ g_free(str);
+ str = tmp;
+ }
+
+ return str;
+}
+
+GSList *bt_string2list(const gchar *str)
+{
+ GSList *l = NULL;
+ gchar **uuids;
+ int i = 0;
+
+ if (!str)
+ return NULL;
+
+ /* FIXME: eglib doesn't support g_strsplit */
+ uuids = g_strsplit(str, " ", 0);
+ if (!uuids)
+ return NULL;
+
+ while (uuids[i]) {
+ l = g_slist_append(l, uuids[i]);
+ i++;
+ }
+
+ g_free(uuids);
+
+ return l;
+}
+
+static inline int resolve_names(int fd, struct sockaddr *host,
+ struct sockaddr *peer, socklen_t len)
+{
+ int err;
+ socklen_t namelen;
+
+ namelen = len;
+ memset(host, 0, len);
+ err = getsockname(fd, host, &namelen);
+ if (err < 0)
+ return err;
+
+ namelen = len;
+ memset(peer, 0, len);
+ err = getpeername(fd, peer, &namelen);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rfcomm_resolver(int fd, char *src, char *dst)
+{
+ struct sockaddr_rc host, peer;
+ socklen_t len;
+ int err;
+
+ len = sizeof(host);
+ err = resolve_names(fd, (struct sockaddr *) &host,
+ (struct sockaddr *) &peer, len);
+ if (err < 0)
+ return err;
+
+ ba2str(&host.rc_bdaddr, src);
+ ba2str(&peer.rc_bdaddr, dst);
+
+ return 0;
+}
+
+static int l2cap_resolver(int fd, char *src, char *dst)
+{
+ struct sockaddr_l2 host, peer;
+ socklen_t len;
+ int err;
+
+ len = sizeof(host);
+ err = resolve_names(fd, (struct sockaddr *) &host,
+ (struct sockaddr *) &peer, len);
+ if (err < 0)
+ return err;
+
+ ba2str(&host.l2_bdaddr, src);
+ ba2str(&peer.l2_bdaddr, dst);
+
+ return 0;
+}
+
+static int sco_resolver(int fd, char *src, char *dst)
+{
+ struct sockaddr_sco host, peer;
+ socklen_t len;
+ int err;
+
+ len = sizeof(host);
+ err = resolve_names(fd, (struct sockaddr *) &host,
+ (struct sockaddr *) &peer, len);
+ if (err < 0)
+ return err;
+
+ ba2str(&host.sco_bdaddr, src);
+ ba2str(&peer.sco_bdaddr, dst);
+
+ return 0;
+}
+
+static gboolean listen_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ BtIO *io = user_data;
+ struct io_context *io_ctxt = io->io_ctxt;
+ int fd, err = 0;
+ GIOChannel *gio;
+ struct sockaddr addr;
+ socklen_t len;
+ bdaddr_t src, dst;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_close(chan);
+ g_io_channel_unref(chan);
+ g_free(io_ctxt);
+ return FALSE;
+ }
+
+ len = sizeof(addr);
+ memset(&addr, 0, len);
+ fd = accept(io_ctxt->fd, &addr, &len);
+ if (fd < 0)
+ goto drop;
+
+ if (io_ctxt->resolver) {
+ err = io_ctxt->resolver(fd, io->src, io->dst);
+ if (err < 0) {
+ close(fd);
+ goto drop;
+ }
+ }
+
+ gio = g_io_channel_unix_new(fd);
+ if (!gio)
+ err = -ENOMEM;
+
+ if (io_ctxt->func)
+ io_ctxt->func(io, err, gio, io_ctxt->user_data);
+ if (io_ctxt->cb) {
+ str2ba(io->src, &src);
+ str2ba(io->dst, &dst);
+ io_ctxt->cb(gio, err, &src, &dst, io_ctxt->user_data);
+ }
+
+ return TRUE;
+
+drop:
+ if (io_ctxt->func)
+ io_ctxt->func(io, -errno, NULL, io_ctxt->user_data);
+ if (io_ctxt->cb)
+ io_ctxt->cb(NULL, err, NULL, NULL, io_ctxt->user_data);
+
+ return TRUE;
+}
+
+static int transport_listen(BtIO *io)
+{
+ struct io_context *io_ctxt = io->io_ctxt;
+ int err;
+
+ err = listen(io_ctxt->fd, 5);
+ if (err < 0)
+ return -errno;
+
+ io_ctxt->io = g_io_channel_unix_new(io_ctxt->fd);
+ if (!io_ctxt->io)
+ return -ENOMEM;
+
+ g_io_add_watch(io_ctxt->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) listen_cb, io);
+
+ return 0;
+}
+
+static gboolean connect_cb(GIOChannel *gio, GIOCondition cond,
+ gpointer user_data)
+{
+ BtIO *io = user_data;
+ struct io_context *io_ctxt = io->io_ctxt;
+ int err = 0, ret;
+ socklen_t len;
+ bdaddr_t src, dst;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ len = sizeof(ret);
+ if (getsockopt(io_ctxt->fd, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
+ err = -errno;
+ goto done;
+ }
+
+ if (ret != 0) {
+ err = -ret;
+ goto done;
+ }
+
+ if (io_ctxt->resolver) {
+ err = io_ctxt->resolver(io_ctxt->fd, io->src, io->dst);
+ if (err < 0)
+ goto done;
+ }
+
+ io_ctxt->io = NULL;
+
+done:
+ if (io_ctxt->func)
+ io_ctxt->func(io, err, gio, io_ctxt->user_data);
+ if (io_ctxt->cb) {
+ str2ba(io->src, &src);
+ str2ba(io->dst, &dst);
+ io_ctxt->cb(gio, err, &src, &dst, io_ctxt->user_data);
+ }
+ if (io_ctxt->io) {
+ g_io_channel_close(io_ctxt->io);
+ g_io_channel_unref(io_ctxt->io);
+ }
+ g_free(io_ctxt);
+
+ return FALSE;
+}
+
+static int transport_connect(BtIO *io, struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct io_context *io_ctxt = io->io_ctxt;
+ int err;
+
+ io_ctxt->io = g_io_channel_unix_new(io_ctxt->fd);
+ if (!io_ctxt->io)
+ return -ENOMEM;
+
+ err = g_io_channel_set_flags(io_ctxt->io, G_IO_FLAG_NONBLOCK, NULL);
+ if (err != G_IO_STATUS_NORMAL)
+ return -EPERM;
+
+ err = connect(io_ctxt->fd, addr, addrlen);
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return -errno;
+
+ g_io_add_watch(io_ctxt->io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) connect_cb, io);
+
+ return 0;
+}
+
+static BtIOError sco_connect(BtIO *io, BtIOFunc func)
+{
+ struct io_context *io_ctxt = io->io_ctxt;
+ struct sockaddr_sco addr;
+ int sk, err;
+
+ io_ctxt->func = func;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sk < 0)
+ return -errno;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ str2ba(io->src, &addr.sco_bdaddr);
+
+ err = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0) {
+ close(sk);
+ return BT_IO_FAILED;
+ }
+
+ io_ctxt->fd = sk;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ str2ba(io->dst, &addr.sco_bdaddr);
+
+ err = transport_connect(io, (struct sockaddr *) &addr,
+ sizeof(addr));
+ if (err < 0) {
+ close(sk);
+ return BT_IO_FAILED;
+ }
+
+ return BT_IO_SUCCESS;
+}
+
+static int l2cap_bind(struct io_context *io_ctxt, const char *address,
+ uint16_t psm, uint16_t mtu, uint32_t flags,
+ struct sockaddr_l2 *addr)
+{
+ int err;
+ struct l2cap_options l2o;
+ struct sockaddr_l2 l2a;
+
+ io_ctxt->fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (io_ctxt->fd < 0)
+ return -errno;
+
+ if (mtu) {
+ socklen_t olen = sizeof(l2o);
+ memset(&l2o, 0, olen);
+ getsockopt(io_ctxt->fd, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen);
+ l2o.imtu = l2o.omtu = mtu;
+ setsockopt(io_ctxt->fd, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o));
+ }
+
+ if (flags) {
+ int opt = flags;
+ err = setsockopt(io_ctxt->fd, SOL_L2CAP, L2CAP_LM, &opt,
+ sizeof(opt));
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return -errno;
+ }
+ }
+
+ memset(addr, 0, sizeof(*addr));
+ addr->l2_family = AF_BLUETOOTH;
+ str2ba(address, &l2a.l2_bdaddr);
+ addr->l2_psm = htobs(psm);
+
+ err = bind(io_ctxt->fd, (struct sockaddr *) addr, sizeof(*addr));
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return -errno;
+ }
+
+ return 0;
+}
+
+static BtIOError l2cap_listen(BtIO *io, BtIOFunc func)
+{
+ struct io_context *io_ctxt = io->io_ctxt;
+ struct sockaddr_l2 addr;
+ BtIOError err;
+
+ io_ctxt->func = func;
+
+ err = l2cap_bind(io_ctxt, io->src, io->psm, io->mtu, io->flags, &addr);
+ if (err < 0)
+ return err;
+
+ err = transport_listen(io);
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return err;
+ }
+
+ return BT_IO_SUCCESS;
+}
+
+static BtIOError l2cap_connect(BtIO *io, BtIOFunc func)
+{
+ struct io_context *io_ctxt = io->io_ctxt;
+ struct sockaddr_l2 l2a;
+ BtIOError err;
+
+ io_ctxt->func = func;
+
+ err = l2cap_bind(io_ctxt, io->src, 0, io->mtu, 0, &l2a);
+ if (err < 0)
+ return err;
+
+ memset(&l2a, 0, sizeof(l2a));
+ l2a.l2_family = AF_BLUETOOTH;
+ str2ba(io->dst, &l2a.l2_bdaddr);
+ l2a.l2_psm = htobs(io->psm);
+
+ err = transport_connect(io, (struct sockaddr *) &l2a,
+ sizeof(l2a));
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return err;
+ }
+
+ return BT_IO_SUCCESS;
+}
+
+static BtIOError rfcomm_bind(struct io_context *io_ctxt, const char *address,
+ uint8_t channel, uint32_t flags,
+ struct sockaddr_rc *addr)
+{
+ BtIOError err;
+
+ io_ctxt->fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (io_ctxt->fd < 0)
+ return BT_IO_FAILED;
+
+ if (flags) {
+ int opt = flags;
+ err = setsockopt(io_ctxt->fd, SOL_RFCOMM, RFCOMM_LM, &opt,
+ sizeof(opt));
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return BT_IO_FAILED;
+ }
+ }
+
+ memset(addr, 0, sizeof(*addr));
+ addr->rc_family = AF_BLUETOOTH;
+ str2ba(address, &addr->rc_bdaddr);
+ addr->rc_channel = channel;
+
+ err = bind(io_ctxt->fd, (struct sockaddr *) addr, sizeof(*addr));
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return BT_IO_FAILED;
+ }
+
+ return BT_IO_SUCCESS;
+}
+
+static BtIOError rfcomm_listen(BtIO *io, BtIOFunc func)
+{
+ struct io_context *io_ctxt = io->io_ctxt;
+ struct sockaddr_rc addr;
+ socklen_t sa_len;
+ BtIOError err;
+
+ io_ctxt->func = func;
+
+ err = rfcomm_bind(io_ctxt, io->src, io->channel, io->flags, &addr);
+ if (err < 0)
+ return err;
+
+ err = transport_listen(io);
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return err;
+ }
+
+ sa_len = sizeof(struct sockaddr_rc);
+ memset(&addr, 0, sizeof(addr));
+ if (getsockname(io_ctxt->fd, (struct sockaddr *) &addr, &sa_len) < 0) {
+ err = -errno;
+ close(io_ctxt->fd);
+ return err;
+ }
+
+ io->channel = addr.rc_channel;
+
+ return BT_IO_SUCCESS;
+}
+
+static BtIOError rfcomm_connect(BtIO *io, BtIOFunc func)
+{
+ struct io_context *io_ctxt = io->io_ctxt;
+ struct sockaddr_rc addr;
+ BtIOError err;
+
+ io_ctxt->func = func;
+
+ err = rfcomm_bind(io_ctxt, io->src, 0, 0, &addr);
+ if (err < 0)
+ return err;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ str2ba(io->dst, &addr.rc_bdaddr);
+ addr.rc_channel = io->channel;
+
+ err = transport_connect(io, (struct sockaddr *) &addr,
+ sizeof(addr));
+ if (err < 0) {
+ close(io_ctxt->fd);
+ return err;
+ }
+
+ return BT_IO_SUCCESS;
+}
+
+static int create_io_context(struct io_context **io_ctxt, BtIOFunc func,
+ gpointer cb, gpointer resolver, gpointer user_data)
+{
+ *io_ctxt = g_try_malloc0(sizeof(struct search_context));
+ if (!*io_ctxt)
+ return -ENOMEM;
+
+ (*io_ctxt)->cb = cb;
+ (*io_ctxt)->func = func;
+ (*io_ctxt)->resolver = resolver;
+ (*io_ctxt)->user_data = user_data;
+
+ return 0;
+}
+
+static void io_context_cleanup(struct io_context *io_ctxt)
+{
+ if (io_ctxt->io) {
+ g_io_channel_close(io_ctxt->io);
+ g_io_channel_unref(io_ctxt->io);
+ }
+ g_free(io_ctxt);
+}
+
+GIOChannel *rfcomm_listen_internal(const bdaddr_t *src, uint8_t *channel,
+ uint32_t flags, bt_io_callback_t cb, void *user_data)
+{
+ BtIO *io;
+ BtIOError err;
+
+ io = bt_io_create(BT_IO_RFCOMM, user_data, NULL);
+ if (!io)
+ return NULL;
+
+ ba2str(src, io->src);
+ io->channel = *channel;
+ io->flags = flags;
+ io->io_ctxt->cb = cb;
+ err = bt_io_listen(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return NULL;
+ }
+
+ *channel = io->channel;
+
+ return io->io_ctxt->io;
+}
+
+GIOChannel *bt_rfcomm_listen_allocate(const bdaddr_t *src, uint8_t *channel,
+ uint32_t flags, bt_io_callback_t cb, void *user_data)
+{
+ if (!channel)
+ return NULL;
+
+ *channel = 0;
+
+ return rfcomm_listen_internal(src, channel, flags, cb, user_data);
+}
+
+GIOChannel *bt_rfcomm_listen(const bdaddr_t *src, uint8_t channel,
+ uint32_t flags, bt_io_callback_t cb, void *user_data)
+{
+ if (channel < 1 || channel > 30)
+ return NULL;
+
+ return rfcomm_listen_internal(src, &channel, flags, cb, user_data);
+
+}
+
+int bt_rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst,
+ uint8_t channel, bt_io_callback_t cb, void *user_data)
+{
+ BtIO *io;
+ BtIOError err;
+
+ io = bt_io_create(BT_IO_RFCOMM, user_data, NULL);
+ if (!io)
+ return -1;
+
+ ba2str(src, io->src);
+ ba2str(dst, io->dst);
+ io->channel = channel;
+ io->io_ctxt->cb = cb;
+ err = bt_io_connect(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return -1;
+ }
+
+ return 0;
+}
+
+GIOChannel *bt_l2cap_listen(const bdaddr_t *src, uint16_t psm, uint16_t mtu,
+ uint32_t flags, bt_io_callback_t cb, void *user_data)
+{
+ BtIO *io;
+ BtIOError err;
+
+ io = bt_io_create(BT_IO_L2CAP, user_data, NULL);
+ if (!io)
+ return NULL;
+
+ ba2str(src, io->src);
+ io->psm = psm;
+ io->mtu = mtu;
+ io->flags = flags;
+ io->io_ctxt->cb = cb;
+ err = bt_io_listen(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return NULL;
+ }
+
+ return io->io_ctxt->io;
+}
+
+int bt_l2cap_connect(const bdaddr_t *src, const bdaddr_t *dst,
+ uint16_t psm, uint16_t mtu, bt_io_callback_t cb,
+ void *user_data)
+{
+ BtIO *io;
+ BtIOError err;
+
+ io = bt_io_create(BT_IO_L2CAP, user_data, NULL);
+ if (!io)
+ return -1;
+
+ ba2str(src, io->src);
+ ba2str(dst, io->dst);
+ io->psm = psm;
+ io->mtu = mtu;
+ io->io_ctxt->cb = cb;
+ err = bt_io_connect(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return -1;
+ }
+
+ return 0;
+}
+
+int bt_sco_connect(const bdaddr_t *src, const bdaddr_t *dst,
+ bt_io_callback_t cb, void *user_data)
+{
+ BtIO *io;
+ BtIOError err;
+
+ io = bt_io_create(BT_IO_SCO, user_data, NULL);
+ if (!io)
+ return -1;
+
+ ba2str(src, io->src);
+ ba2str(dst, io->dst);
+ io->io_ctxt->cb = cb;
+ err = bt_io_connect(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Experiemental bt_io API */
+
+BtIO *bt_io_create(BtIOTransport type, gpointer user_data, GDestroyNotify notify)
+{
+ BtIO *io;
+ int err;
+
+ io = g_new0(BtIO, 1);
+ if (!io)
+ return NULL;
+
+ io->refcount = 1;
+
+ switch (type) {
+ case BT_IO_L2CAP:
+ err = create_io_context(&io->io_ctxt, NULL, NULL,
+ l2cap_resolver, user_data);
+ io->connect = l2cap_connect;
+ io->listen = l2cap_listen;
+ break;
+ case BT_IO_RFCOMM:
+ err = create_io_context(&io->io_ctxt, NULL, NULL,
+ rfcomm_resolver, user_data);
+ io->connect = rfcomm_connect;
+ io->listen = rfcomm_listen;
+ break;
+ case BT_IO_SCO:
+ err = create_io_context(&io->io_ctxt, NULL, NULL,
+ sco_resolver, user_data);
+ io->connect = sco_connect;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (err < 0) {
+ bt_io_unref(io);
+ return NULL;
+ }
+
+ return io;
+}
+
+BtIO *bt_io_ref(BtIO *io)
+{
+ io->refcount++;
+
+ return io;
+}
+
+void bt_io_unref(BtIO *io)
+{
+ io->refcount--;
+
+ if (io->refcount)
+ return;
+
+ io_context_cleanup(io->io_ctxt);
+ g_free(io);
+}
+
+gboolean bt_io_set_source(BtIO *io, const char *address)
+{
+ if (strlen(address) != sizeof(io->src))
+ return FALSE;
+
+ memcpy(io->src, address, sizeof(io->src));
+
+ return TRUE;
+}
+
+const char *bt_io_get_source(BtIO *io)
+{
+ return io->src;
+}
+
+gboolean bt_io_set_destination(BtIO *io, const char *address)
+{
+ if (strlen(address) != sizeof(io->dst))
+ return FALSE;
+
+ memcpy(io->dst, address, sizeof(io->dst));
+
+ return TRUE;
+}
+
+const char *bt_io_get_destination(BtIO *io)
+{
+ return io->dst;
+}
+
+gboolean bt_io_set_flags(BtIO *io, guint32 flags)
+{
+ io->flags = flags;
+
+ return TRUE;
+}
+
+guint32 bt_io_get_flags(BtIO *io)
+{
+ return io->flags;
+}
+
+gboolean bt_io_set_channel(BtIO *io, guint8 channel)
+{
+ if (io->type != BT_IO_RFCOMM)
+ return FALSE;
+
+ io->channel = channel;
+
+ return TRUE;
+}
+
+guint8 bt_io_get_channel(BtIO *io)
+{
+ return io->channel;
+}
+
+gboolean bt_io_set_psm(BtIO *io, guint16 psm)
+{
+ if (io->type != BT_IO_L2CAP)
+ return FALSE;
+
+ io->psm = psm;
+
+ return TRUE;
+}
+
+guint16 bt_io_get_psm(BtIO *io)
+{
+ return io->psm;
+}
+
+gboolean bt_io_set_mtu(BtIO *io, guint16 mtu)
+{
+ io->mtu = mtu;
+
+ return TRUE;
+}
+
+guint16 bt_io_get_mtu(BtIO *io)
+{
+ return io->mtu;
+}
+
+BtIOError bt_io_connect(BtIO *io, const char *uuid, BtIOFunc func)
+{
+ if (!io->connect)
+ return BT_IO_FAILED;
+
+ return io->connect(io, func);
+}
+
+BtIOError bt_io_listen(BtIO *io, const char *uuid, BtIOFunc func)
+{
+ if (!io->listen)
+ return BT_IO_FAILED;
+
+ return io->listen(io, func);
+}
+
+BtIOError bt_io_shutdown(BtIO *io)
+{
+ io_context_cleanup(io->io_ctxt);
+
+ return BT_IO_SUCCESS;
+}
diff --git a/utils/common/glib-helper.h b/utils/common/glib-helper.h
new file mode 100644
index 00000000..6b188f7f
--- /dev/null
+++ b/utils/common/glib-helper.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 set_nonblocking(int fd);
+
+typedef void (*bt_io_callback_t) (GIOChannel *io, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data);
+typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data);
+typedef void (*bt_destroy_t) (gpointer user_data);
+
+int bt_discover_services(const bdaddr_t *src, const bdaddr_t *dst,
+ bt_callback_t cb, void *user_data, bt_destroy_t destroy);
+
+int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
+ uuid_t *uuid, bt_callback_t cb, void *user_data,
+ bt_destroy_t destroy);
+int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst);
+
+gchar *bt_uuid2string(uuid_t *uuid);
+uint16_t bt_string2class(const char *string);
+int bt_string2uuid(uuid_t *uuid, const char *string);
+gchar *bt_list2string(GSList *list);
+GSList *bt_string2list(const gchar *str);
+
+GIOChannel *bt_rfcomm_listen(const bdaddr_t *src, uint8_t channel,
+ uint32_t flags, bt_io_callback_t cb, void *user_data);
+GIOChannel *bt_rfcomm_listen_allocate(const bdaddr_t *src, uint8_t *channel,
+ uint32_t flags, bt_io_callback_t cb, void *user_data);
+int bt_rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst,
+ uint8_t channel, bt_io_callback_t cb, void *user_data);
+
+GIOChannel *bt_l2cap_listen(const bdaddr_t *src, uint16_t psm, uint16_t mtu,
+ uint32_t flags, bt_io_callback_t cb, void *user_data);
+int bt_l2cap_connect(const bdaddr_t *src, const bdaddr_t *dst,
+ uint16_t psm, uint16_t mtu, bt_io_callback_t cb,
+ void *user_data);
+int bt_sco_connect(const bdaddr_t *src, const bdaddr_t *dst,
+ bt_io_callback_t cb, void *user_data);
+
+/* Experiemental bt_io API */
+
+typedef struct bt_io BtIO;
+
+typedef enum {
+ BT_IO_AUTO,
+ BT_IO_L2CAP,
+ BT_IO_RFCOMM,
+ BT_IO_SCO,
+} BtIOTransport;
+
+typedef enum {
+ BT_IO_SUCCESS,
+ BT_IO_FAILED,
+} BtIOError;
+
+typedef void (*BtIOFunc) (BtIO *io, BtIOError err, GIOChannel *chan,
+ gpointer user_data);
+
+BtIO *bt_io_create(BtIOTransport type, gpointer user_data, GDestroyNotify notify);
+BtIO *bt_io_ref(BtIO *io);
+void bt_io_unref(BtIO *io);
+gboolean bt_io_set_source(BtIO *io, const char *address);
+const char *bt_io_get_source(BtIO *io);
+gboolean bt_io_set_destination(BtIO *io, const char *address);
+const char *bt_io_get_destination(BtIO *io);
+gboolean bt_io_set_flags(BtIO *io, guint32 flags);
+guint32 bt_io_get_flags(BtIO *io);
+gboolean bt_io_set_channel(BtIO *io, guint8 channel);
+guint8 bt_io_get_channel(BtIO *io);
+gboolean bt_io_set_psm(BtIO *io, guint16 psm);
+guint16 bt_io_get_psm(BtIO *io);
+gboolean bt_io_set_mtu(BtIO *io, guint16 mtu);
+guint16 bt_io_get_mtu(BtIO *io);
+BtIOError bt_io_connect(BtIO *io, const char *uuid, BtIOFunc func);
+BtIOError bt_io_listen(BtIO *io, const char *uuid, BtIOFunc func);
+BtIOError bt_io_shutdown(BtIO *io);
diff --git a/utils/common/logging.c b/utils/common/logging.c
new file mode 100644
index 00000000..28fc9af5
--- /dev/null
+++ b/utils/common/logging.c
@@ -0,0 +1,106 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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>
+
+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/utils/common/logging.h b/utils/common/logging.h
new file mode 100644
index 00000000..822eb15a
--- /dev/null
+++ b/utils/common/logging.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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, ...);
+void error(const char *format, ...);
+void debug(const char *format, ...);
+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/utils/common/oui.c b/utils/common/oui.c
new file mode 100644
index 00000000..0915afdf
--- /dev/null
+++ b/utils/common/oui.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "oui.h"
+
+/* http://standards.ieee.org/regauth/oui/oui.txt */
+
+#define OUIFILE "/var/lib/misc/oui.txt"
+
+char *ouitocomp(const char *oui)
+{
+ struct stat st;
+ char *str, *map, *off, *end;
+ int fd;
+
+ fd = open("oui.txt", O_RDONLY);
+ if (fd < 0) {
+ fd = open(OUIFILE, O_RDONLY);
+ if (fd < 0) {
+ fd = open("/usr/share/misc/oui.txt", O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ }
+ }
+
+ if (fstat(fd, &st) < 0) {
+ close(fd);
+ return NULL;
+ }
+
+ str = malloc(128);
+ if (!str) {
+ close(fd);
+ return NULL;
+ }
+
+ memset(str, 0, 128);
+
+ map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ free(str);
+ close(fd);
+ return NULL;
+ }
+
+ off = strstr(map, oui);
+ if (off) {
+ off += 18;
+ end = strpbrk(off, "\r\n");
+ strncpy(str, off, end - off);
+ } else {
+ free(str);
+ str = NULL;
+ }
+
+ munmap(map, st.st_size);
+
+ close(fd);
+
+ return str;
+}
+
+int oui2comp(const char *oui, char *comp, size_t size)
+{
+ char *tmp;
+
+ tmp = ouitocomp(oui);
+ if (!tmp)
+ return -1;
+
+ snprintf(comp, size, "%s", tmp);
+
+ free(tmp);
+
+ return 0;
+}
diff --git a/utils/common/oui.h b/utils/common/oui.h
new file mode 100644
index 00000000..991e145c
--- /dev/null
+++ b/utils/common/oui.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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
+ *
+ */
+
+char *ouitocomp(const char *oui);
+int oui2comp(const char *oui, char *comp, size_t size);
diff --git a/utils/common/ppoll.h b/utils/common/ppoll.h
new file mode 100644
index 00000000..7d09d44d
--- /dev/null
+++ b/utils/common/ppoll.h
@@ -0,0 +1,16 @@
+#ifdef ppoll
+#undef ppoll
+#endif
+
+#define ppoll compat_ppoll
+
+static inline int compat_ppoll(struct pollfd *fds, nfds_t nfds,
+ const struct timespec *timeout, const sigset_t *sigmask)
+{
+ if (timeout == NULL)
+ return poll(fds, nfds, -1);
+ else if (timeout->tv_sec == 0)
+ return poll(fds, nfds, 500);
+ else
+ return poll(fds, nfds, timeout->tv_sec * 1000);
+}
diff --git a/utils/common/sdp-glib.c b/utils/common/sdp-glib.c
new file mode 100644
index 00000000..bd27d822
--- /dev/null
+++ b/utils/common/sdp-glib.c
@@ -0,0 +1,239 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "sdp-xml.h"
+
+static int compute_seq_size(sdp_data_t *data)
+{
+ int unit_size = data->unitSize;
+ sdp_data_t *seq = data->val.dataseq;
+
+ for (; seq; seq = seq->next)
+ unit_size += seq->unitSize;
+
+ return unit_size;
+}
+
+struct context_data {
+ sdp_record_t *record;
+ sdp_data_t attr_data;
+ struct sdp_xml_data *stack_head;
+ uint16_t attr_id;
+};
+
+static void element_start(GMarkupParseContext *context,
+ const gchar *element_name, const gchar **attribute_names,
+ const gchar **attribute_values, gpointer user_data, GError **err)
+{
+ struct context_data *ctx_data = user_data;
+
+ if (!strcmp(element_name, "record"))
+ return;
+
+ if (!strcmp(element_name, "attribute")) {
+ int i;
+ for (i = 0; attribute_names[i]; i++) {
+ if (!strcmp(attribute_names[i], "id")) {
+ ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
+ break;
+ }
+ }
+ debug("New attribute 0x%04x", ctx_data->attr_id);
+ return;
+ }
+
+ if (ctx_data->stack_head) {
+ struct sdp_xml_data *newelem = sdp_xml_data_alloc();
+ newelem->next = ctx_data->stack_head;
+ ctx_data->stack_head = newelem;
+ } else {
+ ctx_data->stack_head = sdp_xml_data_alloc();
+ ctx_data->stack_head->next = NULL;
+ }
+
+ if (!strcmp(element_name, "sequence"))
+ ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
+ else if (!strcmp(element_name, "alternate"))
+ ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
+ else {
+ int i;
+ /* Parse value, name, encoding */
+ for (i = 0; attribute_names[i]; i++) {
+ if (!strcmp(attribute_names[i], "value")) {
+ int curlen = strlen(ctx_data->stack_head->text);
+ int attrlen = strlen(attribute_values[i]);
+
+ /* Ensure we're big enough */
+ while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) {
+ sdp_xml_data_expand(ctx_data->stack_head);
+ }
+
+ memcpy(ctx_data->stack_head->text + curlen,
+ attribute_values[i], attrlen);
+ ctx_data->stack_head->text[curlen + attrlen] = '\0';
+ }
+
+ if (!strcmp(attribute_names[i], "encoding")) {
+ if (!strcmp(attribute_values[i], "hex"))
+ ctx_data->stack_head->type = 1;
+ }
+
+ if (!strcmp(attribute_names[i], "name")) {
+ ctx_data->stack_head->name = strdup(attribute_values[i]);
+ }
+ }
+
+ ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
+ ctx_data->stack_head, ctx_data->record);
+
+ if (ctx_data->stack_head->data == NULL)
+ error("Can't parse element %s", element_name);
+ }
+}
+
+static void element_end(GMarkupParseContext *context,
+ const gchar *element_name, gpointer user_data, GError **err)
+{
+ struct context_data *ctx_data = user_data;
+ struct sdp_xml_data *elem;
+
+ if (!strcmp(element_name, "record"))
+ return;
+
+ if (!strcmp(element_name, "attribute")) {
+ if (ctx_data->stack_head && ctx_data->stack_head->data) {
+ int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
+ ctx_data->stack_head->data);
+ if (ret == -1)
+ debug("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);
+ }
+ return;
+ }
+
+ if (!strcmp(element_name, "sequence")) {
+ ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
+
+ if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
+ ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
+ ctx_data->stack_head->data->dtd = SDP_SEQ32;
+ } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
+ ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
+ ctx_data->stack_head->data->dtd = SDP_SEQ16;
+ } else {
+ ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
+ }
+ } else if (!strcmp(element_name, "alternate")) {
+ ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
+
+ if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
+ ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
+ ctx_data->stack_head->data->dtd = SDP_ALT32;
+ } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
+ ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
+ ctx_data->stack_head->data->dtd = SDP_ALT16;
+ } else {
+ ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
+ }
+ }
+
+ if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
+ ctx_data->stack_head->next->data) {
+ switch (ctx_data->stack_head->next->data->dtd) {
+ case SDP_SEQ8:
+ case SDP_SEQ16:
+ case SDP_SEQ32:
+ case SDP_ALT8:
+ case SDP_ALT16:
+ case SDP_ALT32:
+ ctx_data->stack_head->next->data->val.dataseq =
+ sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
+ ctx_data->stack_head->data);
+ ctx_data->stack_head->data = NULL;
+ break;
+ }
+
+ elem = ctx_data->stack_head;
+ ctx_data->stack_head = ctx_data->stack_head->next;
+
+ sdp_xml_data_free(elem);
+ }
+}
+
+static GMarkupParser parser = {
+ element_start, element_end, NULL, NULL, NULL
+};
+
+sdp_record_t *sdp_xml_parse_record(const char *data, int size)
+{
+ GMarkupParseContext *ctx;
+ struct context_data *ctx_data;
+ sdp_record_t *record;
+
+ ctx_data = malloc(sizeof(*ctx_data));
+ if (!ctx_data)
+ return NULL;
+
+ record = sdp_record_alloc();
+ if (!record) {
+ free(ctx_data);
+ return NULL;
+ }
+
+ memset(ctx_data, 0, sizeof(*ctx_data));
+ ctx_data->record = record;
+
+ ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
+
+ if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
+ error("XML parsing error");
+ g_markup_parse_context_free(ctx);
+ sdp_record_free(record);
+ free(ctx_data);
+ return NULL;
+ }
+
+ g_markup_parse_context_free(ctx);
+
+ free(ctx_data);
+
+ return record;
+}
diff --git a/utils/common/sdp-xml.c b/utils/common/sdp-xml.c
new file mode 100644
index 00000000..1e1e07c3
--- /dev/null
+++ b/utils/common/sdp-xml.c
@@ -0,0 +1,793 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "logging.h"
+#include "sdp-xml.h"
+
+#define STRBUFSIZE 1024
+#define MAXINDENT 64
+
+static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
+ void *data, void (*appender)(void *, const char *))
+{
+ int i, hex;
+ char buf[STRBUFSIZE];
+ char indent[MAXINDENT];
+ char next_indent[MAXINDENT];
+
+ if (!value)
+ return;
+
+ if (indent_level >= MAXINDENT)
+ indent_level = MAXINDENT - 2;
+
+ for (i = 0; i < indent_level; i++) {
+ indent[i] = '\t';
+ next_indent[i] = '\t';
+ }
+
+ indent[i] = '\0';
+ next_indent[i] = '\t';
+ next_indent[i + 1] = '\0';
+
+ buf[STRBUFSIZE - 1] = '\0';
+
+ switch (value->dtd) {
+ case SDP_DATA_NIL:
+ appender(data, indent);
+ appender(data, "<nil/>\n");
+ break;
+
+ case SDP_BOOL:
+ appender(data, indent);
+ appender(data, "<boolean value=\"");
+ appender(data, value->val.uint8 ? "true" : "false");
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UINT8:
+ appender(data, indent);
+ appender(data, "<uint8 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UINT16:
+ appender(data, indent);
+ appender(data, "<uint16 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UINT32:
+ appender(data, indent);
+ appender(data, "<uint32 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UINT64:
+ appender(data, indent);
+ appender(data, "<uint64 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UINT128:
+ appender(data, indent);
+ appender(data, "<uint128 value=\"");
+
+ for (i = 0; i < 16; i++) {
+ sprintf(&buf[i * 2], "%02x",
+ (unsigned char) value->val.uint128.data[i]);
+ }
+
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_INT8:
+ appender(data, indent);
+ appender(data, "<int8 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_INT16:
+ appender(data, indent);
+ appender(data, "<int16 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_INT32:
+ appender(data, indent);
+ appender(data, "<int32 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_INT64:
+ appender(data, indent);
+ appender(data, "<int64 value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_INT128:
+ appender(data, indent);
+ appender(data, "<int128 value=\"");
+
+ for (i = 0; i < 16; i++) {
+ sprintf(&buf[i * 2], "%02x",
+ (unsigned char) value->val.int128.data[i]);
+ }
+ appender(data, buf);
+
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UUID16:
+ appender(data, indent);
+ appender(data, "<uuid value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UUID32:
+ appender(data, indent);
+ appender(data, "<uuid value=\"");
+ snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_UUID128:
+ appender(data, indent);
+ appender(data, "<uuid value=\"");
+
+ snprintf(buf, STRBUFSIZE - 1,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[0],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[1],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[2],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[3],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[4],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[5],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[6],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[7],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[8],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[9],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[10],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[11],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[12],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[13],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[14],
+ (unsigned char) value->val.uuid.value.
+ uuid128.data[15]);
+
+ appender(data, buf);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_TEXT_STR8:
+ case SDP_TEXT_STR16:
+ case SDP_TEXT_STR32:
+ {
+ hex = 0;
+
+ int num_chars_to_escape = 0;
+
+ for (i = 0; i < value->unitSize; i++) {
+ if (i == (value->unitSize - 1)
+ && value->val.str[i] == '\0')
+ break;
+ if (!isprint(value->val.str[i])) {
+ hex = 1;
+ break;
+ }
+
+ /* XML is evil, must do this... */
+ if ((value->val.str[i] == '<') ||
+ (value->val.str[i] == '>') ||
+ (value->val.str[i] == '"') ||
+ (value->val.str[i] == '&'))
+ num_chars_to_escape++;
+ }
+
+ appender(data, indent);
+
+ appender(data, "<text ");
+
+ char *strBuf = 0;
+
+ if (hex) {
+ appender(data, "encoding=\"hex\" ");
+ strBuf = (char *) malloc(sizeof(char)
+ * ((value->unitSize-1) * 2 + 1));
+
+ /* Unit Size seems to include the size for dtd
+ It is thus off by 1
+ This is safe for Normal strings, but not
+ hex encoded data */
+ for (i = 0; i < (value->unitSize-1); i++)
+ sprintf(&strBuf[i*sizeof(char)*2],
+ "%02x",
+ (unsigned char) value->val.str[i]);
+
+ strBuf[(value->unitSize-1) * 2] = '\0';
+ }
+ else {
+ int j;
+ /* escape the XML disallowed chars */
+ strBuf = (char *)
+ malloc(sizeof(char) *
+ (value->unitSize + 1 + num_chars_to_escape * 4));
+ for (i = 0, j = 0; i < value->unitSize; i++) {
+ if (value->val.str[i] == '&') {
+ strBuf[j++] = '&';
+ strBuf[j++] = 'a';
+ strBuf[j++] = 'm';
+ strBuf[j++] = 'p';
+ }
+ else if (value->val.str[i] == '<') {
+ strBuf[j++] = '&';
+ strBuf[j++] = 'l';
+ strBuf[j++] = 't';
+ }
+ else if (value->val.str[i] == '>') {
+ strBuf[j++] = '&';
+ strBuf[j++] = 'g';
+ strBuf[j++] = 't';
+ }
+ else if (value->val.str[i] == '"') {
+ strBuf[j++] = '&';
+ strBuf[j++] = 'q';
+ strBuf[j++] = 'u';
+ strBuf[j++] = 'o';
+ strBuf[j++] = 't';
+ }
+ else {
+ strBuf[j++] = value->val.str[i];
+ }
+ }
+
+ strBuf[j] = '\0';
+ }
+
+ appender(data, "value=\"");
+ appender(data, strBuf);
+ appender(data, "\" />\n");
+ free(strBuf);
+ break;
+ }
+
+ case SDP_URL_STR8:
+ case SDP_URL_STR16:
+ case SDP_URL_STR32:
+ appender(data, indent);
+ appender(data, "<url value=\"");
+ appender(data, value->val.str);
+ appender(data, "\" />\n");
+ break;
+
+ case SDP_SEQ8:
+ case SDP_SEQ16:
+ case SDP_SEQ32:
+ appender(data, indent);
+ appender(data, "<sequence>\n");
+
+ convert_raw_data_to_xml(value->val.dataseq,
+ indent_level + 1, data, appender);
+
+ appender(data, indent);
+ appender(data, "</sequence>\n");
+
+ break;
+
+ case SDP_ALT8:
+ case SDP_ALT16:
+ case SDP_ALT32:
+ appender(data, indent);
+
+ appender(data, "<alternate>\n");
+
+ convert_raw_data_to_xml(value->val.dataseq,
+ indent_level + 1, data, appender);
+ appender(data, indent);
+
+ appender(data, "</alternate>\n");
+
+ break;
+ }
+
+ convert_raw_data_to_xml(value->next, indent_level, data, appender);
+}
+
+struct conversion_data {
+ void *data;
+ void (*appender)(void *data, const char *);
+};
+
+static void convert_raw_attr_to_xml_func(void *val, void *data)
+{
+ struct conversion_data *cd = (struct conversion_data *) data;
+ sdp_data_t *value = (sdp_data_t *) val;
+ char buf[STRBUFSIZE];
+
+ buf[STRBUFSIZE - 1] = '\0';
+ snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
+ value->attrId);
+ cd->appender(cd->data, buf);
+
+ if (data)
+ convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
+ else
+ cd->appender(cd->data, "\t\tNULL\n");
+
+ cd->appender(cd->data, "\t</attribute>\n");
+}
+
+/*
+ * Will convert the sdp record to XML. The appender and data can be used
+ * to control where to output the record (e.g. file or a data buffer). The
+ * appender will be called repeatedly with data and the character buffer
+ * (containing parts of the generated XML) to append.
+ */
+void convert_sdp_record_to_xml(sdp_record_t *rec,
+ void *data, void (*appender)(void *, const char *))
+{
+ struct conversion_data cd;
+
+ cd.data = data;
+ cd.appender = appender;
+
+ if (rec && rec->attrlist) {
+ appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
+ appender(data, "<record>\n");
+ sdp_list_foreach(rec->attrlist,
+ convert_raw_attr_to_xml_func, &cd);
+ appender(data, "</record>\n");
+ }
+}
+
+static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
+{
+ uint128_t val;
+ int i;
+ int j;
+
+ char buf[3];
+
+ memset(&val, 0, sizeof(val));
+
+ buf[2] = '\0';
+
+ for (j = 0, i = 0; i < strlen(data);) {
+ if (data[i] == '-') {
+ i++;
+ continue;
+ }
+
+ buf[0] = data[i];
+ buf[1] = data[i + 1];
+
+ val.data[j++] = strtoul(buf, 0, 16);
+ i += 2;
+ }
+
+ return sdp_data_alloc(SDP_UUID128, &val);
+}
+
+sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
+{
+ sdp_data_t *ret;
+ char *endptr;
+ uint32_t val;
+ uint16_t val2;
+ int len;
+
+ len = strlen(data);
+
+ if (len == 36) {
+ ret = sdp_xml_parse_uuid128(data);
+ goto result;
+ }
+
+ val = strtoll(data, &endptr, 16);
+
+ /* Couldn't parse */
+ if (*endptr != '\0')
+ return NULL;
+
+ if (val > USHRT_MAX) {
+ ret = sdp_data_alloc(SDP_UUID32, &val);
+ goto result;
+ }
+
+ val2 = val;
+
+ ret = sdp_data_alloc(SDP_UUID16, &val2);
+
+result:
+ if (record && ret)
+ sdp_pattern_add_uuid(record, &ret->val.uuid);
+
+ return ret;
+}
+
+sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
+{
+ char *endptr;
+ sdp_data_t *ret = NULL;
+
+ switch (dtd) {
+ case SDP_BOOL:
+ {
+ uint8_t val = 0;
+
+ if (!strcmp("true", data)) {
+ val = 1;
+ }
+
+ else if (!strcmp("false", data)) {
+ val = 0;
+ }
+ else {
+ return NULL;
+ }
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_INT8:
+ {
+ int8_t val = strtoul(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_UINT8:
+ {
+ uint8_t val = strtoul(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_INT16:
+ {
+ int16_t val = strtoul(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_UINT16:
+ {
+ uint16_t val = strtoul(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_INT32:
+ {
+ int32_t val = strtoul(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_UINT32:
+ {
+ uint32_t val = strtoul(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_INT64:
+ {
+ int64_t val = strtoull(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_UINT64:
+ {
+ uint64_t val = strtoull(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_INT128:
+ case SDP_UINT128:
+ {
+ uint128_t val;
+ int i = 0;
+ char buf[3];
+
+ buf[2] = '\0';
+
+ for (; i < 32; i += 2) {
+ buf[0] = data[i];
+ buf[1] = data[i + 1];
+
+ val.data[i >> 1] = strtoul(buf, 0, 16);
+ }
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ };
+
+ return ret;
+}
+
+static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
+{
+ int len = strlen(data);
+ char *text;
+
+ if (encoding == SDP_XML_ENCODING_NORMAL) {
+ text = strdup(data);
+ *length = len;
+ } else {
+ char buf[3], *decoded;
+ int i;
+
+ decoded = malloc((len >> 1) + 1);
+
+ /* Ensure the string is a power of 2 */
+ len = (len >> 1) << 1;
+
+ buf[2] = '\0';
+
+ for (i = 0; i < len; i += 2) {
+ buf[0] = data[i];
+ buf[1] = data[i + 1];
+
+ decoded[i >> 1] = strtoul(buf, 0, 16);
+ }
+
+ decoded[len >> 1] = '\0';
+ text = decoded;
+ *length = len >> 1;
+ }
+
+ return text;
+}
+
+sdp_data_t *sdp_xml_parse_url(const char *data)
+{
+ uint8_t dtd = SDP_URL_STR8;
+ char *url;
+ uint32_t length;
+ sdp_data_t *ret;
+
+ url = sdp_xml_parse_string_decode(data,
+ SDP_XML_ENCODING_NORMAL, &length);
+
+ if (length > UCHAR_MAX)
+ dtd = SDP_URL_STR16;
+
+ ret = sdp_data_alloc_with_length(dtd, url, length);
+
+ debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
+
+ free(url);
+
+ return ret;
+}
+
+sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
+{
+ uint8_t dtd = SDP_TEXT_STR8;
+ char *text;
+ uint32_t length;
+ sdp_data_t *ret;
+
+ text = sdp_xml_parse_string_decode(data, encoding, &length);
+
+ if (length > UCHAR_MAX)
+ dtd = SDP_TEXT_STR16;
+
+ ret = sdp_data_alloc_with_length(dtd, text, length);
+
+ debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
+
+ free(text);
+
+ return ret;
+}
+
+sdp_data_t *sdp_xml_parse_nil(const char *data)
+{
+ return sdp_data_alloc(SDP_DATA_NIL, 0);
+}
+
+#define DEFAULT_XML_DATA_SIZE 1024
+
+struct sdp_xml_data *sdp_xml_data_alloc()
+{
+ struct sdp_xml_data *elem;
+
+ elem = malloc(sizeof(struct sdp_xml_data));
+ if (!elem)
+ return NULL;
+
+ memset(elem, 0, sizeof(struct sdp_xml_data));
+
+ /* Null terminate the text */
+ elem->size = DEFAULT_XML_DATA_SIZE;
+ elem->text = malloc(DEFAULT_XML_DATA_SIZE);
+ elem->text[0] = '\0';
+
+ return elem;
+}
+
+void sdp_xml_data_free(struct sdp_xml_data *elem)
+{
+ if (elem->data)
+ sdp_data_free(elem->data);
+
+ if (elem->name)
+ free(elem->name);
+
+ if (elem->text)
+
+ free(elem->text);
+ free(elem);
+}
+
+struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
+{
+ char *newbuf;
+
+ newbuf = malloc(elem->size * 2);
+ if (!newbuf)
+ return NULL;
+
+ memcpy(newbuf, elem->text, elem->size);
+ elem->size *= 2;
+ free(elem->text);
+
+ elem->text = newbuf;
+
+ return elem;
+}
+
+sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
+ sdp_record_t *record)
+{
+ const char *data = elem->text;
+
+ if (!strcmp(el, "boolean"))
+ return sdp_xml_parse_int(data, SDP_BOOL);
+ else if (!strcmp(el, "uint8"))
+ return sdp_xml_parse_int(data, SDP_UINT8);
+ else if (!strcmp(el, "uint16"))
+ return sdp_xml_parse_int(data, SDP_UINT16);
+ else if (!strcmp(el, "uint32"))
+ return sdp_xml_parse_int(data, SDP_UINT32);
+ else if (!strcmp(el, "uint64"))
+ return sdp_xml_parse_int(data, SDP_UINT64);
+ else if (!strcmp(el, "uint128"))
+ return sdp_xml_parse_int(data, SDP_UINT128);
+ else if (!strcmp(el, "int8"))
+ return sdp_xml_parse_int(data, SDP_INT8);
+ else if (!strcmp(el, "int16"))
+ return sdp_xml_parse_int(data, SDP_INT16);
+ else if (!strcmp(el, "int32"))
+ return sdp_xml_parse_int(data, SDP_INT32);
+ else if (!strcmp(el, "int64"))
+ return sdp_xml_parse_int(data, SDP_INT64);
+ else if (!strcmp(el, "int128"))
+ return sdp_xml_parse_int(data, SDP_INT128);
+ else if (!strcmp(el, "uuid"))
+ return sdp_xml_parse_uuid(data, record);
+ else if (!strcmp(el, "url"))
+ return sdp_xml_parse_url(data);
+ else if (!strcmp(el, "text"))
+ return sdp_xml_parse_text(data, elem->type);
+ else if (!strcmp(el, "nil"))
+ return sdp_xml_parse_nil(data);
+
+ return NULL;
+}
diff --git a/utils/common/sdp-xml.h b/utils/common/sdp-xml.h
new file mode 100644
index 00000000..adb173e2
--- /dev/null
+++ b/utils/common/sdp-xml.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+
+#ifndef __SDP_XML_H
+#define __SDP_XML_H
+
+#include <bluetooth/sdp.h>
+
+#define SDP_XML_ENCODING_NORMAL 0
+#define SDP_XML_ENCODING_HEX 1
+
+void convert_sdp_record_to_xml(sdp_record_t *rec,
+ void *user_data, void (*append_func) (void *, const char *));
+
+sdp_data_t *sdp_xml_parse_nil(const char *data);
+sdp_data_t *sdp_xml_parse_text(const char *data, char encoding);
+sdp_data_t *sdp_xml_parse_url(const char *data);
+sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd);
+sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record);
+
+struct sdp_xml_data {
+ char *text; /* Pointer to the current buffer */
+ int size; /* Size of the current buffer */
+ sdp_data_t *data; /* The current item being built */
+ struct sdp_xml_data *next; /* Next item on the stack */
+ char type; /* 0 = Text or Hexadecimal */
+ char *name; /* Name, optional in the dtd */
+ /* TODO: What is it used for? */
+};
+
+struct sdp_xml_data *sdp_xml_data_alloc();
+void sdp_xml_data_free(struct sdp_xml_data *elem);
+struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem);
+
+sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
+ sdp_record_t *record);
+
+sdp_record_t *sdp_xml_parse_record(const char *data, int size);
+
+#endif /* __SDP_XML_H */
diff --git a/utils/common/test_textfile.c b/utils/common/test_textfile.c
new file mode 100644
index 00000000..1bb024eb
--- /dev/null
+++ b/utils/common/test_textfile.c
@@ -0,0 +1,187 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "textfile.h"
+
+static void print_entry(char *key, char *value, void *data)
+{
+ printf("%s %s\n", key, value);
+}
+
+int main(int argc, char *argv[])
+{
+ char filename[] = "/tmp/textfile";
+ char key[18], value[512], *str;
+ int i, j, fd, err, size, max = 10;
+
+ size = getpagesize();
+ printf("System uses a page size of %d bytes\n\n", size);
+
+ fd = creat(filename, 0644);
+ err = ftruncate(fd, 0);
+
+ memset(value, 0, sizeof(value));
+ for (i = 0; i < (size / sizeof(value)); i++)
+ err = write(fd, value, sizeof(value));
+
+ close(fd);
+
+ sprintf(key, "11:11:11:11:11:11");
+ str = textfile_get(filename, key);
+
+ err = truncate(filename, 0);
+
+
+ sprintf(key, "00:00:00:00:00:00");
+ if (textfile_del(filename, key) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ memset(value, 0, sizeof(value));
+ if (textfile_put(filename, key, value) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ str = textfile_get(filename, key);
+ if (!str)
+ fprintf(stderr, "No value for %s\n", key);
+ else
+ free(str);
+
+ snprintf(value, sizeof(value), "Test");
+ if (textfile_put(filename, key, value) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ if (textfile_put(filename, key, value) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ if (textfile_put(filename, key, value) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ if (textfile_del(filename, key) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ str = textfile_get(filename, key);
+ if (str) {
+ fprintf(stderr, "Found value for %s\n", key);
+ free(str);
+ }
+
+ for (i = 1; i < max + 1; i++) {
+ sprintf(key, "00:00:00:00:00:%02X", i);
+
+ memset(value, 0, sizeof(value));
+ for (j = 0; j < i; j++)
+ value[j] = 'x';
+
+ printf("%s %s\n", key, value);
+
+ if (textfile_put(filename, key, value) < 0) {
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+ break;
+ }
+
+ str = textfile_get(filename, key);
+ if (!str)
+ fprintf(stderr, "No value for %s\n", key);
+ else
+ free(str);
+ }
+
+
+ sprintf(key, "00:00:00:00:00:%02X", max);
+
+ memset(value, 0, sizeof(value));
+ for (j = 0; j < max; j++)
+ value[j] = 'y';
+
+ if (textfile_put(filename, key, value) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ sprintf(key, "00:00:00:00:00:%02X", 1);
+
+ memset(value, 0, sizeof(value));
+ for (j = 0; j < max; j++)
+ value[j] = 'z';
+
+ if (textfile_put(filename, key, value) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ printf("\n");
+
+ for (i = 1; i < max + 1; i++) {
+ sprintf(key, "00:00:00:00:00:%02X", i);
+
+ str = textfile_get(filename, key);
+ if (str) {
+ printf("%s %s\n", key, str);
+ free(str);
+ }
+ }
+
+
+ sprintf(key, "00:00:00:00:00:%02X", 2);
+
+ if (textfile_del(filename, key) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ sprintf(key, "00:00:00:00:00:%02X", max - 3);
+
+ if (textfile_del(filename, key) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ printf("\n");
+
+ textfile_foreach(filename, print_entry, NULL);
+
+
+ sprintf(key, "00:00:00:00:00:%02X", 1);
+
+ if (textfile_del(filename, key) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ sprintf(key, "00:00:00:00:00:%02X", max);
+
+ if (textfile_del(filename, key) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ sprintf(key, "00:00:00:00:00:%02X", max + 1);
+
+ if (textfile_del(filename, key) < 0)
+ fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
+
+ printf("\n");
+
+ textfile_foreach(filename, print_entry, NULL);
+
+ return 0;
+}
diff --git a/utils/common/textfile.c b/utils/common/textfile.c
new file mode 100644
index 00000000..eef0f96a
--- /dev/null
+++ b/utils/common/textfile.c
@@ -0,0 +1,463 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+
+#include "textfile.h"
+
+int create_dirs(const char *filename, const mode_t mode)
+{
+ struct stat st;
+ char dir[PATH_MAX + 1], *prev, *next;
+ int err;
+
+ err = stat(filename, &st);
+ if (!err && S_ISREG(st.st_mode))
+ return 0;
+
+ memset(dir, 0, PATH_MAX + 1);
+ strcat(dir, "/");
+
+ prev = strchr(filename, '/');
+
+ while (prev) {
+ next = strchr(prev + 1, '/');
+ if (!next)
+ break;
+
+ if (next - prev == 1) {
+ prev = next;
+ continue;
+ }
+
+ strncat(dir, prev + 1, next - prev);
+ mkdir(dir, mode);
+
+ prev = next;
+ }
+
+ return 0;
+}
+
+int create_file(const char *filename, const mode_t mode)
+{
+ int fd;
+
+ umask(S_IWGRP | S_IWOTH);
+ create_dirs(filename, S_IRUSR | S_IWUSR | S_IXUSR |
+ S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+
+ fd = open(filename, O_RDWR | O_CREAT, mode);
+ if (fd < 0)
+ return fd;
+
+ close(fd);
+
+ return 0;
+}
+
+int create_name(char *buf, size_t size, const char *path, const char *address, const char *name)
+{
+ return snprintf(buf, size, "%s/%s/%s", path, address, name);
+}
+
+static inline char *find_key(char *map, size_t size, const char *key, size_t len, int icase)
+{
+ char *ptr = map;
+ size_t ptrlen = size;
+
+ while (ptrlen > len + 1) {
+ int cmp = (icase) ? strncasecmp(ptr, key, len) : strncmp(ptr, key, len);
+ if (cmp == 0) {
+ if (ptr == map)
+ return ptr;
+
+ if ((*(ptr - 1) == '\r' || *(ptr - 1) == '\n') &&
+ *(ptr + len) == ' ')
+ return ptr;
+ }
+
+ if (icase) {
+ char *p1 = memchr(ptr + 1, tolower(*key), ptrlen - 1);
+ char *p2 = memchr(ptr + 1, toupper(*key), ptrlen - 1);
+
+ if (!p1)
+ ptr = p2;
+ else if (!p2)
+ ptr = p1;
+ else
+ ptr = (p1 < p2) ? p1 : p2;
+ } else
+ ptr = memchr(ptr + 1, *key, ptrlen - 1);
+
+ if (!ptr)
+ return NULL;
+
+ ptrlen = size - (ptr - map);
+ }
+
+ return NULL;
+}
+
+static inline int write_key_value(int fd, const char *key, const char *value)
+{
+ char *str;
+ size_t size;
+ int err = 0;
+
+ size = strlen(key) + strlen(value) + 2;
+
+ str = malloc(size + 1);
+ if (!str)
+ return ENOMEM;
+
+ sprintf(str, "%s %s\n", key, value);
+
+ if (write(fd, str, size) < 0)
+ err = errno;
+
+ free(str);
+
+ return err;
+}
+
+static int write_key(const char *pathname, const char *key, const char *value, int icase)
+{
+ struct stat st;
+ char *map, *off, *end, *str;
+ off_t size, pos; size_t base, len;
+ int fd, err = 0;
+
+ fd = open(pathname, O_RDWR);
+ if (fd < 0)
+ return -errno;
+
+ if (flock(fd, LOCK_EX) < 0) {
+ err = errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ if (!size) {
+ if (value) {
+ pos = lseek(fd, size, SEEK_SET);
+ err = write_key_value(fd, key, value);
+ }
+ goto unlock;
+ }
+
+ map = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_LOCKED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = errno;
+ goto unlock;
+ }
+
+ len = strlen(key);
+ off = find_key(map, size, key, len, icase);
+ if (!off) {
+ if (value) {
+ munmap(map, size);
+ pos = lseek(fd, size, SEEK_SET);
+ err = write_key_value(fd, key, value);
+ }
+ goto unlock;
+ }
+
+ base = off - map;
+
+ end = strpbrk(off, "\r\n");
+ if (!end) {
+ err = EILSEQ;
+ goto unmap;
+ }
+
+ if (value && (strlen(value) == end - off - len - 1) &&
+ !strncmp(off + len + 1, value, end - off - len - 1))
+ goto unmap;
+
+ len = strspn(end, "\r\n");
+ end += len;
+
+ len = size - (end - map);
+ if (!len) {
+ munmap(map, size);
+ if (ftruncate(fd, base) < 0) {
+ err = errno;
+ goto unlock;
+ }
+ pos = lseek(fd, base, SEEK_SET);
+ if (value)
+ err = write_key_value(fd, key, value);
+
+ goto unlock;
+ }
+
+ if (len < 0 || len > size) {
+ err = EILSEQ;
+ goto unmap;
+ }
+
+ str = malloc(len);
+ if (!str) {
+ err = errno;
+ goto unmap;
+ }
+
+ memcpy(str, end, len);
+
+ munmap(map, size);
+ if (ftruncate(fd, base) < 0) {
+ err = errno;
+ free(str);
+ goto unlock;
+ }
+ pos = lseek(fd, base, SEEK_SET);
+ if (value)
+ err = write_key_value(fd, key, value);
+
+ if (write(fd, str, len) < 0)
+ err = errno;
+
+ free(str);
+
+ goto unlock;
+
+unmap:
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+ errno = err;
+
+ return -err;
+}
+
+static char *read_key(const char *pathname, const char *key, int icase)
+{
+ struct stat st;
+ char *map, *off, *end, *str = NULL;
+ off_t size; size_t len;
+ int fd, err = 0;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ if (flock(fd, LOCK_SH) < 0) {
+ err = errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = errno;
+ goto unlock;
+ }
+
+ len = strlen(key);
+ off = find_key(map, size, key, len, icase);
+ if (!off) {
+ err = EILSEQ;
+ goto unmap;
+ }
+
+ end = strpbrk(off, "\r\n");
+ if (!end) {
+ err = EILSEQ;
+ goto unmap;
+ }
+
+ str = malloc(end - off - len);
+ if (!str) {
+ err = EILSEQ;
+ goto unmap;
+ }
+
+ memset(str, 0, end - off - len);
+ strncpy(str, off + len + 1, end - off - len - 1);
+
+unmap:
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+ errno = err;
+
+ return str;
+}
+
+int textfile_put(const char *pathname, const char *key, const char *value)
+{
+ return write_key(pathname, key, value, 0);
+}
+
+int textfile_caseput(const char *pathname, const char *key, const char *value)
+{
+ return write_key(pathname, key, value, 1);
+}
+
+int textfile_del(const char *pathname, const char *key)
+{
+ return write_key(pathname, key, NULL, 0);
+}
+
+int textfile_casedel(const char *pathname, const char *key)
+{
+ return write_key(pathname, key, NULL, 1);
+}
+
+char *textfile_get(const char *pathname, const char *key)
+{
+ return read_key(pathname, key, 0);
+}
+
+char *textfile_caseget(const char *pathname, const char *key)
+{
+ return read_key(pathname, key, 1);
+}
+
+int textfile_foreach(const char *pathname,
+ void (*func)(char *key, char *value, void *data), void *data)
+{
+ struct stat st;
+ char *map, *off, *end, *key, *value;
+ off_t size; size_t len;
+ int fd, err = 0;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ if (flock(fd, LOCK_SH) < 0) {
+ err = errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = errno;
+ goto unlock;
+ }
+
+ off = map;
+
+ while (1) {
+ end = strpbrk(off, " ");
+ if (!end) {
+ err = EILSEQ;
+ break;
+ }
+
+ len = end - off;
+
+ key = malloc(len + 1);
+ if (!key) {
+ err = errno;
+ break;
+ }
+
+ memset(key, 0, len + 1);
+ memcpy(key, off, len);
+
+ off = end + 1;
+
+ end = strpbrk(off, "\r\n");
+ if (!end) {
+ err = EILSEQ;
+ free(key);
+ break;
+ }
+
+ len = end - off;
+
+ value = malloc(len + 1);
+ if (!value) {
+ err = errno;
+ free(key);
+ break;
+ }
+
+ memset(value, 0, len + 1);
+ memcpy(value, off, len);
+
+ func(key, value, data);
+
+ free(key);
+ free(value);
+
+ off = end + 1;
+ }
+
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+ errno = err;
+
+ return 0;
+}
diff --git a/utils/common/textfile.h b/utils/common/textfile.h
new file mode 100644
index 00000000..b2276e3a
--- /dev/null
+++ b/utils/common/textfile.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 __TEXTFILE_H
+#define __TEXTFILE_H
+
+int create_dirs(const char *filename, const mode_t mode);
+int create_file(const char *filename, const mode_t mode);
+int create_name(char *buf, size_t size, const char *path,
+ const char *address, const char *name);
+
+int textfile_put(const char *pathname, const char *key, const char *value);
+int textfile_caseput(const char *pathname, const char *key, const char *value);
+int textfile_del(const char *pathname, const char *key);
+int textfile_casedel(const char *pathname, const char *key);
+char *textfile_get(const char *pathname, const char *key);
+char *textfile_caseget(const char *pathname, const char *key);
+
+int textfile_foreach(const char *pathname,
+ void (*func)(char *key, char *value, void *data), void *data);
+
+#endif /* __TEXTFILE_H */
diff --git a/utils/common/uinput.h b/utils/common/uinput.h
new file mode 100644
index 00000000..dca87829
--- /dev/null
+++ b/utils/common/uinput.h
@@ -0,0 +1,586 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 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 __UINPUT_H
+#define __UINPUT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+/* Events */
+
+#define EV_SYN 0x00
+#define EV_KEY 0x01
+#define EV_REL 0x02
+#define EV_ABS 0x03
+#define EV_MSC 0x04
+#define EV_LED 0x11
+#define EV_SND 0x12
+#define EV_REP 0x14
+#define EV_FF 0x15
+#define EV_PWR 0x16
+#define EV_FF_STATUS 0x17
+#define EV_MAX 0x1f
+
+/* Synchronization events */
+
+#define SYN_REPORT 0
+#define SYN_CONFIG 1
+
+/* Keys and buttons */
+
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+#define KEY_103RD 84
+#define KEY_F13 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_F14 89
+#define KEY_F15 90
+#define KEY_F16 91
+#define KEY_F17 92
+#define KEY_F18 93
+#define KEY_F19 94
+#define KEY_F20 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+#define KEY_F21 120
+#define KEY_F22 121
+#define KEY_F23 122
+#define KEY_F24 123
+#define KEY_KPCOMMA 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128
+#define KEY_AGAIN 129
+#define KEY_PROPS 130
+#define KEY_UNDO 131
+#define KEY_FRONT 132
+#define KEY_COPY 133
+#define KEY_OPEN 134
+#define KEY_PASTE 135
+#define KEY_FIND 136
+#define KEY_CUT 137
+#define KEY_HELP 138
+#define KEY_MENU 139
+#define KEY_CALC 140
+#define KEY_SETUP 141
+#define KEY_SLEEP 142
+#define KEY_WAKEUP 143
+#define KEY_FILE 144
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152
+#define KEY_DIRECTION 153
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156
+#define KEY_COMPUTER 157
+#define KEY_BACK 158
+#define KEY_FORWARD 159
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169
+#define KEY_ISO 170
+#define KEY_CONFIG 171
+#define KEY_HOMEPAGE 172
+#define KEY_REFRESH 173
+#define KEY_EXIT 174
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+
+#define KEY_INTL1 181
+#define KEY_INTL2 182
+#define KEY_INTL3 183
+#define KEY_INTL4 184
+#define KEY_INTL5 185
+#define KEY_INTL6 186
+#define KEY_INTL7 187
+#define KEY_INTL8 188
+#define KEY_INTL9 189
+#define KEY_LANG1 190
+#define KEY_LANG2 191
+#define KEY_LANG3 192
+#define KEY_LANG4 193
+#define KEY_LANG5 194
+#define KEY_LANG6 195
+#define KEY_LANG7 196
+#define KEY_LANG8 197
+#define KEY_LANG9 198
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206
+#define KEY_PLAY 207
+
+#define KEY_UNKNOWN 220
+
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_A 0x130
+#define BTN_B 0x131
+#define BTN_C 0x132
+#define BTN_X 0x133
+#define BTN_Y 0x134
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define KEY_OK 0x160
+#define KEY_SELECT 0x161
+#define KEY_GOTO 0x162
+#define KEY_CLEAR 0x163
+#define KEY_POWER2 0x164
+#define KEY_OPTION 0x165
+#define KEY_INFO 0x166
+#define KEY_TIME 0x167
+#define KEY_VENDOR 0x168
+#define KEY_ARCHIVE 0x169
+#define KEY_PROGRAM 0x16a
+#define KEY_CHANNEL 0x16b
+#define KEY_FAVORITES 0x16c
+#define KEY_EPG 0x16d
+#define KEY_PVR 0x16e
+#define KEY_MHP 0x16f
+#define KEY_LANGUAGE 0x170
+#define KEY_TITLE 0x171
+#define KEY_SUBTITLE 0x172
+#define KEY_ANGLE 0x173
+#define KEY_ZOOM 0x174
+#define KEY_MODE 0x175
+#define KEY_KEYBOARD 0x176
+#define KEY_SCREEN 0x177
+#define KEY_PC 0x178
+#define KEY_TV 0x179
+#define KEY_TV2 0x17a
+#define KEY_VCR 0x17b
+#define KEY_VCR2 0x17c
+#define KEY_SAT 0x17d
+#define KEY_SAT2 0x17e
+#define KEY_CD 0x17f
+#define KEY_TAPE 0x180
+#define KEY_RADIO 0x181
+#define KEY_TUNER 0x182
+#define KEY_PLAYER 0x183
+#define KEY_TEXT 0x184
+#define KEY_DVD 0x185
+#define KEY_AUX 0x186
+#define KEY_MP3 0x187
+#define KEY_AUDIO 0x188
+#define KEY_VIDEO 0x189
+#define KEY_DIRECTORY 0x18a
+#define KEY_LIST 0x18b
+#define KEY_MEMO 0x18c
+#define KEY_CALENDAR 0x18d
+#define KEY_RED 0x18e
+#define KEY_GREEN 0x18f
+#define KEY_YELLOW 0x190
+#define KEY_BLUE 0x191
+#define KEY_CHANNELUP 0x192
+#define KEY_CHANNELDOWN 0x193
+#define KEY_FIRST 0x194
+#define KEY_LAST 0x195
+#define KEY_AB 0x196
+#define KEY_NEXT 0x197
+#define KEY_RESTART 0x198
+#define KEY_SLOW 0x199
+#define KEY_SHUFFLE 0x19a
+#define KEY_BREAK 0x19b
+#define KEY_PREVIOUS 0x19c
+#define KEY_DIGITS 0x19d
+#define KEY_TEEN 0x19e
+#define KEY_TWEN 0x19f
+
+#define KEY_FRAMEBACK 0x1b2
+#define KEY_FRAMEFORWARD 0x1b3
+#define KEY_CONTEXT_MENU 0x1fb
+
+#define KEY_MAX 0x1ff
+
+/* Relative axes */
+
+#define REL_X 0x00
+#define REL_Y 0x01
+#define REL_Z 0x02
+#define REL_RX 0x03
+#define REL_RY 0x04
+#define REL_RZ 0x05
+#define REL_HWHEEL 0x06
+#define REL_DIAL 0x07
+#define REL_WHEEL 0x08
+#define REL_MISC 0x09
+#define REL_MAX 0x0f
+
+/* Absolute axes */
+
+#define ABS_X 0x00
+#define ABS_Y 0x01
+#define ABS_Z 0x02
+#define ABS_RX 0x03
+#define ABS_RY 0x04
+#define ABS_RZ 0x05
+#define ABS_THROTTLE 0x06
+#define ABS_RUDDER 0x07
+#define ABS_WHEEL 0x08
+#define ABS_GAS 0x09
+#define ABS_BRAKE 0x0a
+#define ABS_HAT0X 0x10
+#define ABS_HAT0Y 0x11
+#define ABS_HAT1X 0x12
+#define ABS_HAT1Y 0x13
+#define ABS_HAT2X 0x14
+#define ABS_HAT2Y 0x15
+#define ABS_HAT3X 0x16
+#define ABS_HAT3Y 0x17
+#define ABS_PRESSURE 0x18
+#define ABS_DISTANCE 0x19
+#define ABS_TILT_X 0x1a
+#define ABS_TILT_Y 0x1b
+#define ABS_TOOL_WIDTH 0x1c
+#define ABS_VOLUME 0x20
+#define ABS_MISC 0x28
+#define ABS_MAX 0x3f
+
+/* Switch events */
+
+#define SW_0 0x00
+#define SW_1 0x01
+#define SW_2 0x02
+#define SW_3 0x03
+#define SW_4 0x04
+#define SW_5 0x05
+#define SW_6 0x06
+#define SW_7 0x07
+#define SW_MAX 0x0f
+
+/* Misc events */
+
+#define MSC_SERIAL 0x00
+#define MSC_PULSELED 0x01
+#define MSC_GESTURE 0x02
+#define MSC_RAW 0x03
+#define MSC_SCAN 0x04
+#define MSC_MAX 0x07
+
+/* LEDs */
+
+#define LED_NUML 0x00
+#define LED_CAPSL 0x01
+#define LED_SCROLLL 0x02
+#define LED_COMPOSE 0x03
+#define LED_KANA 0x04
+#define LED_SLEEP 0x05
+#define LED_SUSPEND 0x06
+#define LED_MUTE 0x07
+#define LED_MISC 0x08
+#define LED_MAIL 0x09
+#define LED_CHARGING 0x0a
+#define LED_MAX 0x0f
+
+/* Autorepeat values */
+
+#define REP_DELAY 0x00
+#define REP_PERIOD 0x01
+#define REP_MAX 0x01
+
+/* Sounds */
+
+#define SND_CLICK 0x00
+#define SND_BELL 0x01
+#define SND_TONE 0x02
+#define SND_MAX 0x07
+
+/* Identifiers */
+
+#define ID_BUS 0
+#define ID_VENDOR 1
+#define ID_PRODUCT 2
+#define ID_VERSION 3
+
+#define BUS_PCI 0x01
+#define BUS_ISAPNP 0x02
+#define BUS_USB 0x03
+#define BUS_HIL 0x04
+#define BUS_BLUETOOTH 0x05
+
+#define BUS_ISA 0x10
+#define BUS_I8042 0x11
+#define BUS_XTKBD 0x12
+#define BUS_RS232 0x13
+#define BUS_GAMEPORT 0x14
+#define BUS_PARPORT 0x15
+#define BUS_AMIGA 0x16
+#define BUS_ADB 0x17
+#define BUS_I2C 0x18
+#define BUS_HOST 0x19
+#define BUS_GSC 0x1A
+
+/* User input interface */
+
+#define UINPUT_IOCTL_BASE 'U'
+
+#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
+#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
+
+#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
+#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
+#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
+#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
+#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
+#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
+#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
+#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
+#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
+#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
+
+#ifndef NBITS
+#define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1)
+#endif
+
+#define UINPUT_MAX_NAME_SIZE 80
+
+struct uinput_id {
+ uint16_t bustype;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+};
+
+struct uinput_dev {
+ char name[UINPUT_MAX_NAME_SIZE];
+ struct uinput_id id;
+ int ff_effects_max;
+ int absmax[ABS_MAX + 1];
+ int absmin[ABS_MAX + 1];
+ int absfuzz[ABS_MAX + 1];
+ int absflat[ABS_MAX + 1];
+};
+
+struct uinput_event {
+ struct timeval time;
+ uint16_t type;
+ uint16_t code;
+ int32_t value;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UINPUT_H */
diff --git a/utils/config.guess b/utils/config.guess
new file mode 100755
index 00000000..951383e3
--- /dev/null
+++ b/utils/config.guess
@@ -0,0 +1,1516 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2007-05-17'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:* | ix86xen:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:[3456]*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ EM64T | authenticamd)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa:Linux:*:*)
+ echo xtensa-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^LIBC/{
+ s: ::g
+ p
+ }'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/utils/config.h.in b/utils/config.h.in
new file mode 100644
index 00000000..a1e7d0d7
--- /dev/null
+++ b/utils/config.h.in
@@ -0,0 +1,83 @@
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Directory for the configuration files */
+#undef CONFIGDIR
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have USB library. */
+#undef HAVE_LIBUSB
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you need the dbus_watch_get_unix_fd() function. */
+#undef NEED_DBUS_WATCH_GET_UNIX_FD
+
+/* Define to 1 if you need the ppoll() function. */
+#undef NEED_PPOLL
+
+/* Define to 1 if you need the usb_get_busses() function. */
+#undef NEED_USB_GET_BUSSES
+
+/* Define to 1 if you need the usb_interrupt_read() function. */
+#undef NEED_USB_INTERRUPT_READ
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Directory for the service programs */
+#undef SERVICEDIR
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Directory for the storage files */
+#undef STORAGEDIR
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#undef YYTEXT_POINTER
diff --git a/utils/config.sub b/utils/config.sub
new file mode 100755
index 00000000..c060f448
--- /dev/null
+++ b/utils/config.sub
@@ -0,0 +1,1626 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2007-04-29'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/utils/configure b/utils/configure
new file mode 100755
index 00000000..98fb29e7
--- /dev/null
+++ b/utils/configure
@@ -0,0 +1,13503 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.61.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+ if (eval ":") 2>/dev/null; then
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+
+ if test $as_have_required = yes && (eval ":
+(as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=\$LINENO
+ as_lineno_2=\$LINENO
+ test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+ test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+ :
+else
+ as_candidate_shells=
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ case $as_dir in
+ /*)
+ for as_base in sh bash ksh sh5; do
+ as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+ done;;
+ esac
+done
+IFS=$as_save_IFS
+
+
+ for as_shell in $as_candidate_shells $SHELL; do
+ # Try only shells that exist, to save several forks.
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+ CONFIG_SHELL=$as_shell
+ as_have_required=yes
+ if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+ (exit $1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+ break
+fi
+
+fi
+
+ done
+
+ if test "x$CONFIG_SHELL" != x; then
+ for as_var in BASH_ENV ENV
+ do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ done
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+ if test $as_have_required = no; then
+ echo This script requires a shell more modern than all the
+ echo shells that I found on your system. Please install a
+ echo modern shell, or manually run the script under such a
+ echo shell if you do have one.
+ { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+ echo No shell found that supports shell functions.
+ echo Please tell autoconf@gnu.org about your system,
+ echo including any error possibly output before this
+ echo message
+}
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. Blame Lee
+ # E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+ # Remove one level of quotation (which was required for Make).
+ ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','`
+ ;;
+esac
+
+echo=${ECHO-echo}
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+ for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+ # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+ if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+ echo_test_string=`eval $cmd` &&
+ (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+ then
+ break
+ fi
+ done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ :
+else
+ # The Solaris, AIX, and Digital Unix default echo programs unquote
+ # backslashes. This makes it impossible to quote backslashes using
+ # echo "$something" | sed 's/\\/\\\\/g'
+ #
+ # So, first we look for a working echo in the user's PATH.
+
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for dir in $PATH /usr/ucb; do
+ IFS="$lt_save_ifs"
+ if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+ test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$dir/echo"
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+
+ if test "X$echo" = Xecho; then
+ # We didn't find a better echo, so look for alternatives.
+ if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # This shell has a builtin print -r that does the trick.
+ echo='print -r'
+ elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+ test "X$CONFIG_SHELL" != X/bin/ksh; then
+ # If we have ksh, try running configure again with it.
+ ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ export ORIGINAL_CONFIG_SHELL
+ CONFIG_SHELL=/bin/ksh
+ export CONFIG_SHELL
+ exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
+ else
+ # Try using printf.
+ echo='printf %s\n'
+ if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+ echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ # Cool, printf works
+ :
+ elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+ export CONFIG_SHELL
+ SHELL="$CONFIG_SHELL"
+ export SHELL
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+ test "X$echo_testing_string" = 'X\t' &&
+ echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+ test "X$echo_testing_string" = "X$echo_test_string"; then
+ echo="$CONFIG_SHELL $0 --fallback-echo"
+ else
+ # maybe with a smaller string...
+ prev=:
+
+ for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+ if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+ then
+ break
+ fi
+ prev="$cmd"
+ done
+
+ if test "$prev" != 'sed 50q "$0"'; then
+ echo_test_string=`eval $prev`
+ export echo_test_string
+ exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
+ else
+ # Oops. We lost completely, so just stick with echo.
+ echo=echo
+ fi
+ fi
+ fi
+ fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+ ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
+fi
+
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_default_prefix=/usr/local
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+am__isrc
+CYGPATH_W
+PACKAGE
+VERSION
+ACLOCAL
+AUTOCONF
+AUTOMAKE
+AUTOHEADER
+MAKEINFO
+install_sh
+STRIP
+INSTALL_STRIP_PROGRAM
+mkdir_p
+AWK
+SET_MAKE
+am__leading_dot
+AMTAR
+am__tar
+am__untar
+MAINTAINER_MODE_TRUE
+MAINTAINER_MODE_FALSE
+MAINT
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+DEPDIR
+am__include
+am__quote
+AMDEP_TRUE
+AMDEP_FALSE
+AMDEPBACKSLASH
+CCDEPMODE
+am__fastdepCC_TRUE
+am__fastdepCC_FALSE
+YACC
+YFLAGS
+LEX
+LEX_OUTPUT_ROOT
+LEXLIB
+build
+build_cpu
+build_vendor
+build_os
+host
+host_cpu
+host_vendor
+host_os
+SED
+GREP
+EGREP
+LN_S
+ECHO
+AR
+RANLIB
+CPP
+LIBTOOL
+PKG_CONFIG
+BLUEZ_CFLAGS
+BLUEZ_LIBS
+GLIB_CFLAGS
+GLIB_LIBS
+GMODULE_CFLAGS
+GMODULE_LIBS
+DBUS_CFLAGS
+DBUS_LIBS
+ALSA_CFLAGS
+ALSA_LIBS
+GSTREAMER_CFLAGS
+GSTREAMER_LIBS
+GSTREAMER_PLUGINSDIR
+USB_CFLAGS
+USB_LIBS
+NETLINK_CFLAGS
+NETLINK_LIBS
+SNDFILE_CFLAGS
+SNDFILE_LIBS
+GLIB_TRUE
+GLIB_FALSE
+GDBUS_CFLAGS
+GDBUS_LIBS
+SBC_CFLAGS
+SBC_LIBS
+SNDFILE_TRUE
+SNDFILE_FALSE
+NETLINK_TRUE
+NETLINK_FALSE
+USB_TRUE
+USB_FALSE
+SBC_TRUE
+SBC_FALSE
+ALSA_TRUE
+ALSA_FALSE
+GSTREAMER_TRUE
+GSTREAMER_FALSE
+AUDIOPLUGIN_TRUE
+AUDIOPLUGIN_FALSE
+INPUTPLUGIN_TRUE
+INPUTPLUGIN_FALSE
+SERIALPLUGIN_TRUE
+SERIALPLUGIN_FALSE
+NETWORKPLUGIN_TRUE
+NETWORKPLUGIN_FALSE
+HIDD_TRUE
+HIDD_FALSE
+PAND_TRUE
+PAND_FALSE
+DUND_TRUE
+DUND_FALSE
+CUPS_TRUE
+CUPS_FALSE
+TEST_TRUE
+TEST_FALSE
+TOOLS_TRUE
+TOOLS_FALSE
+BCCMD_TRUE
+BCCMD_FALSE
+HID2HCI_TRUE
+HID2HCI_FALSE
+DFUTOOL_TRUE
+DFUTOOL_FALSE
+MANPAGES_TRUE
+MANPAGES_FALSE
+CONFIGFILES_TRUE
+CONFIGFILES_FALSE
+INITSCRIPTS_TRUE
+INITSCRIPTS_FALSE
+PCMCIARULES_TRUE
+PCMCIARULES_FALSE
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+YACC
+YFLAGS
+CPP
+PKG_CONFIG
+BLUEZ_CFLAGS
+BLUEZ_LIBS
+GLIB_CFLAGS
+GLIB_LIBS
+GMODULE_CFLAGS
+GMODULE_LIBS
+DBUS_CFLAGS
+DBUS_LIBS
+ALSA_CFLAGS
+ALSA_LIBS
+GSTREAMER_CFLAGS
+GSTREAMER_LIBS
+USB_CFLAGS
+USB_LIBS
+NETLINK_CFLAGS
+NETLINK_LIBS
+SNDFILE_CFLAGS
+SNDFILE_LIBS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+ eval enable_$ac_feature=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+ eval enable_$ac_feature=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+ eval with_$ac_package=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+ eval with_$ac_package=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ { echo "$as_me: error: Working directory cannot be determined" >&2
+ { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ { echo "$as_me: error: pwd does not report name of working directory" >&2
+ { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+ { (exit 1); exit 1; }; }
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --enable-static[=PKGS] build static libraries [default=no]
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --disable-fortify disable compile time buffer checks
+ --disable-pie disable position independent executables flag
+ --disable-glib disable GLib support
+ --disable-network disable network plugin
+ --disable-serial disable serial plugin
+ --disable-input disable input plugin
+ --disable-audio disable audio plugin
+ --enable-gstreamer enable GStreamer support
+ --enable-alsa enable ALSA support
+ --enable-usb enable USB support
+ --enable-netlink enable NETLINK support
+ --enable-tools install Bluetooth utilities
+ --enable-bccmd install BCCMD interface utility
+ --enable-hid2hci install HID mode switching utility
+ --enable-dfutool install DFU firmware upgrade utility
+ --enable-hidd install HID daemon
+ --enable-pand install PAN daemon
+ --enable-dund install DUN daemon
+ --enable-cups install CUPS backend support
+ --enable-test install test programs
+ --enable-manpages install Bluetooth manual pages
+ --enable-configfiles install Bluetooth config files
+ --enable-initscripts install Bluetooth boot scripts
+ --enable-pcmciarules install PCMCIA udev rules
+ --enable-debug enable compiling with debugging information
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ YACC The `Yet Another C Compiler' implementation to use. Defaults to
+ the first program found out of: `bison -y', `byacc', `yacc'.
+ YFLAGS The list of arguments that will be passed by default to $YACC.
+ This script will default YFLAGS to the empty string to avoid a
+ default value of `-d' given by some make applications.
+ CPP C preprocessor
+ PKG_CONFIG path to pkg-config utility
+ BLUEZ_CFLAGS
+ C compiler flags for BLUEZ, overriding pkg-config
+ BLUEZ_LIBS linker flags for BLUEZ, overriding pkg-config
+ GLIB_CFLAGS C compiler flags for GLIB, overriding pkg-config
+ GLIB_LIBS linker flags for GLIB, overriding pkg-config
+ GMODULE_CFLAGS
+ C compiler flags for GMODULE, overriding pkg-config
+ GMODULE_LIBS
+ linker flags for GMODULE, overriding pkg-config
+ DBUS_CFLAGS C compiler flags for DBUS, overriding pkg-config
+ DBUS_LIBS linker flags for DBUS, overriding pkg-config
+ ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config
+ ALSA_LIBS linker flags for ALSA, overriding pkg-config
+ GSTREAMER_CFLAGS
+ C compiler flags for GSTREAMER, overriding pkg-config
+ GSTREAMER_LIBS
+ linker flags for GSTREAMER, overriding pkg-config
+ USB_CFLAGS C compiler flags for USB, overriding pkg-config
+ USB_LIBS linker flags for USB, overriding pkg-config
+ NETLINK_CFLAGS
+ C compiler flags for NETLINK, overriding pkg-config
+ NETLINK_LIBS
+ linker flags for NETLINK, overriding pkg-config
+ SNDFILE_CFLAGS
+ C compiler flags for SNDFILE, overriding pkg-config
+ SNDFILE_LIBS
+ linker flags for SNDFILE, overriding pkg-config
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" || continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.61. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args '$ac_arg'"
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ *) $as_unset $ac_var ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+ set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+ set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+ set x "$ac_default_prefix/share/config.site" \
+ "$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+am__api_version='1.10'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&5
+echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $. echo might interpret backslashes.
+# By default was `s,x,x', remove it if useless.
+cat <<\_ACEOF >conftest.sed
+s/[\\$]/&&/g;s/;s,x,x,$//
+_ACEOF
+program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
+rm -f conftest.sed
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5
+echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; }
+if test -z "$MKDIR_P"; then
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+done
+IFS=$as_save_IFS
+
+fi
+
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ test -d ./--version && rmdir ./--version
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5
+echo "${ECHO_T}$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+ [\\/$]* | ?:[\\/]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AWK="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; }
+set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ SET_MAKE=
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE=bluez-utils
+ VERSION=3.35
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+{ echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6; }
+ # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ { echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5
+echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6; }
+ if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+
+
+
+ if (test "${CFLAGS}" = ""); then
+ CFLAGS="-Wall -O2"
+ fi
+
+ if (test "${prefix}" = "NONE"); then
+ if (test "$sysconfdir" = '${prefix}/etc'); then
+ sysconfdir='/etc'
+
+ fi
+
+ if (test "$localstatedir" = '${prefix}/var'); then
+ localstatedir='/var'
+
+ fi
+
+ if (test "$libexecdir" = '${exec_prefix}/libexec'); then
+ libexecdir='/lib'
+
+ fi
+
+ if (test "$mandir" = '${prefix}/man'); then
+ mandir='${prefix}/share/man'
+
+ fi
+
+ prefix="${ac_default_prefix}"
+ fi
+
+ if (test "${libdir}" = '${exec_prefix}/lib'); then
+ libdir="${prefix}/lib"
+ fi
+
+ if (test "$sysconfdir" = '${prefix}/etc'); then
+ configdir="${prefix}/etc/bluetooth"
+ else
+ configdir="${sysconfdir}/bluetooth"
+ fi
+
+ if (test "$localstatedir" = '${prefix}/var'); then
+ storagedir="${prefix}/var/lib/bluetooth"
+ else
+ storagedir="${localstatedir}/lib/bluetooth"
+ fi
+
+ servicedir="${libdir}/bluetooth"
+
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGDIR "${configdir}"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define STORAGEDIR "${storagedir}"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define SERVICEDIR "${servicedir}"
+_ACEOF
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler --version >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -v >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -V >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort. b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions. Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ CFLAGS=""
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_c89=$ac_arg
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+ xno)
+ { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+
+
+{ echo "$as_me:$LINENO: result: $_am_result" >&5
+echo "${ECHO_T}$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+ { echo "$as_me:$LINENO: checking whether ${CC-cc} accepts -fPIE" >&5
+echo $ECHO_N "checking whether ${CC-cc} accepts -fPIE... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_pie+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_pie=yes
+ else
+ ac_cv_prog_cc_pie=no
+ fi
+ rm -rf conftest*
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_pie" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_pie" >&6; }
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+for ac_prog in 'bison -y' byacc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_YACC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_YACC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+ { echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+
+for ac_prog in flex lex
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_LEX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LEX="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+ { echo "$as_me:$LINENO: result: $LEX" >&5
+echo "${ECHO_T}$LEX" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+ cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { yyless (input () != 0); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+ return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ (ac_try="$LEX conftest.l"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$LEX conftest.l") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ echo "$as_me:$LINENO: checking lex output file root" >&5
+echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_root+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+if test -f lex.yy.c; then
+ ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+ ac_cv_prog_lex_root=lexyy
+else
+ { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5
+echo "$as_me: error: cannot find output from $LEX; giving up" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+ { echo "$as_me:$LINENO: checking lex library" >&5
+echo $ECHO_N "checking lex library... $ECHO_C" >&6; }
+if test "${ac_cv_lib_lex+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ ac_save_LIBS=$LIBS
+ ac_cv_lib_lex='none needed'
+ for ac_lib in '' -lfl -ll; do
+ LIBS="$ac_lib $ac_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_lex=$ac_lib
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ test "$ac_cv_lib_lex" != 'none needed' && break
+ done
+ LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5
+echo "${ECHO_T}$ac_cv_lib_lex" >&6; }
+ test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5
+echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent. Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_prog_lex_yytext_pointer=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define YYTEXT_POINTER 1
+_ACEOF
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = :; then
+ LEX=${am_missing_run}flex
+fi
+
+
+
+
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=no
+fi
+
+
+
+# Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+# Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+{ echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+echo "$as_me: error: invalid value of canonical build" >&2;}
+ { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+echo "$as_me: error: invalid value of canonical host" >&2;}
+ { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
+echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6; }
+if test "${lt_cv_path_SED+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$lt_ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$lt_ac_prog$ac_exec_ext"; }; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+
+fi
+
+SED=$lt_cv_path_SED
+
+{ echo "$as_me:$LINENO: result: $SED" >&5
+echo "${ECHO_T}$SED" >&6; }
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_path_GREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+ # Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ ac_count=`expr $ac_count + 1`
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+ $ac_path_GREP_found && break 3
+ done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+ { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+ # Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ ac_count=`expr $ac_count + 1`
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+ $ac_path_EGREP_found && break 3
+ done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+ { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { echo "$as_me:$LINENO: checking for GNU ld" >&5
+echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; }
+else
+ { echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+{ echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+{ echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
+echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6; }
+if test "${lt_cv_ld_reload_flag+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
+echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+{ echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
+echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6; }
+if test "${lt_cv_path_NM+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5
+echo "${ECHO_T}$lt_cv_path_NM" >&6; }
+NM="$lt_cv_path_NM"
+
+{ echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6; }
+fi
+
+{ echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5
+echo $ECHO_N "checking how to recognize dependent libraries... $ECHO_C" >&6; }
+if test "${lt_cv_deplibs_check_method+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+nto-qnx*)
+ lt_cv_deplibs_check_method=unknown
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
+echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6; }
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line 4889 "configure"' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ libsuff=64
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5
+echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6; }
+if test "${lt_cv_cc_needs_belf+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ lt_cv_cc_needs_belf=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ lt_cv_cc_needs_belf=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5
+echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *) LD="${LD-ld} -64" ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+ ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+
+# find the maximum length of command line arguments
+{ echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
+echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6; }
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \
+ = "XX$teststring") >/dev/null 2>&1 &&
+ new_result=`expr "X$teststring" : ".*" 2>&1` &&
+ lt_cv_sys_max_cmd_len=$new_result &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on massive
+ # amounts of additional arguments before passing them to the linker.
+ # It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
+echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6; }
+fi
+
+
+
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5
+echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6; }
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*) # Its linker distinguishes data from code symbols
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ ;;
+linux* | k*bsd*-gnu)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDGIRSTW]'
+ lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+ lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
+ (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if grep ' nm_test_var$' "$nlist" >/dev/null; then
+ if grep ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+ cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr_t address;
+}
+lt_preloaded_symbols[] =
+{
+EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+ cat <<\EOF >> conftest.$ac_ext
+ {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -f conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { echo "$as_me:$LINENO: result: failed" >&5
+echo "${ECHO_T}failed" >&6; }
+else
+ { echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6; }
+fi
+
+{ echo "$as_me:$LINENO: checking for objdir" >&5
+echo $ECHO_N "checking for objdir... $ECHO_C" >&6; }
+if test "${lt_cv_objdir+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5
+echo "${ECHO_T}$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AR="ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { echo "$as_me:$LINENO: result: $STRIP" >&5
+echo "${ECHO_T}$STRIP" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+echo "${ECHO_T}$ac_ct_STRIP" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
+echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { echo "$as_me:$LINENO: checking for file" >&5
+echo $ECHO_N "checking for file... $ECHO_C" >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+echo "${ECHO_T}$MAGIC_CMD" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+enable_dlopen=no
+enable_win32_dll=no
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then
+ withval=$with_pic; pic_mode="$withval"
+else
+ pic_mode=default
+fi
+
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+
+
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+
+
+{ echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6; }
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:6660: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:6664: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+{ echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6; }
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ hpux*)
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ darwin*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ case $cc_basename in
+ xlc*)
+ lt_prog_compiler_pic='-qnocommon'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ linux* | k*bsd*-gnu)
+ case $cc_basename in
+ icc* | ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Sun\ F*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic" >&6; }
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+
+{ echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6; }
+if test "${lt_prog_compiler_pic_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:6950: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:6954: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_pic_works=yes
+ fi
+ fi
+ $rm conftest*
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6; }
+if test "${lt_prog_compiler_static_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_prog_compiler_static_works=yes
+ fi
+ else
+ lt_prog_compiler_static_works=yes
+ fi
+ fi
+ $rm conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
+echo "${ECHO_T}$lt_prog_compiler_static_works" >&6; }
+
+if test x"$lt_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+{ echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $rm -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:7054: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:7058: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $rm conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+ $rm out/* && rmdir out
+ cd ..
+ rmdir conftest
+ $rm conftest*
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6; }
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6; }
+ hard_links=yes
+ $rm conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { echo "$as_me:$LINENO: result: $hard_links" >&5
+echo "${ECHO_T}$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+{ echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ enable_shared_with_static_runtimes=no
+ archive_cmds=
+ archive_expsym_cmds=
+ old_archive_From_new_cmds=
+ old_archive_from_expsyms_cmds=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ thread_safe_flag_spec=
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_direct=no
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ link_all_deplibs=unknown
+ hardcode_automatic=no
+ module_cmds=
+ module_expsym_cmds=
+ always_export_symbols=no
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ extract_expsyms_cmds=
+ # Just being paranoid about ensuring that cc_basename is set.
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+ case $host_os in
+ cygwin* | mingw* | pw32*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+ if test "$with_gnu_ld" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>/dev/null` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix3* | aix4* | aix5*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+
+ # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+ # that the semantics of dynamic libraries on AmigaOS, at least up
+ # to version 4, is to share data among multiple programs linked
+ # with the same dynamic library. Since this doesn't match the
+ # behavior of shared libraries on other platforms, we can't use
+ # them.
+ ld_shlibs=no
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | k*bsd*-gnu)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ tmp_addflag=
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ *)
+ tmp_sharedflag='-shared' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test $supports_anon_versioning = yes; then
+ archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ $echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix4* | aix5*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an empty executable.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ # see comment about different semantics on the GNU ld section
+ ld_shlibs=no
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_From_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ allow_undefined_flag='${wl}-undefined ${wl}suppress'
+ ;;
+ *) # Darwin 1.3 on
+ if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+ allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ else
+ case ${MACOSX_DEPLOYMENT_TARGET} in
+ 10.[012])
+ allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+ ;;
+ 10.*)
+ allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ whole_archive_flag_spec=''
+ link_all_deplibs=yes
+ if test "$GCC" = yes ; then
+ output_verbose_link_cmd='echo'
+ archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ else
+ case $cc_basename in
+ xlc*)
+ output_verbose_link_cmd='echo'
+ archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring'
+ module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+ # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+ archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ hardcode_direct=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_ld='-rpath $libdir'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z text'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+ else
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+ fi
+
+{ echo "$as_me:$LINENO: result: $ld_shlibs" >&5
+echo "${ECHO_T}$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6; }
+ $rm conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+ (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ then
+ archive_cmds_need_lc=no
+ else
+ archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $rm conftest*
+ { echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5
+echo "${ECHO_T}$archive_cmds_need_lc" >&6; }
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+{ echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6; }
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ sys_lib_search_path_spec=`echo $lt_search_path_spec`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix4* | aix5*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $rm \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+ ;;
+ mingw*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+ if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH printed by
+ # mingw gcc, but we are running on Cygwin. Gcc prints its search
+ # path with ; separators, and with drive letters. We can handle the
+ # drive letters (cygwin fileutils understands them), so leave them,
+ # especially as we might pass files found there to a mingw objdump,
+ # which wouldn't understand a cygwinified path. Ahh.
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555.
+ postinstall_cmds='chmod 555 $lib'
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+nto-qnx*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ shlibpath_overrides_runpath=no
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ shlibpath_overrides_runpath=yes
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+echo "${ECHO_T}$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+{ echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+ test -n "$runpath_var" || \
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existant directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ echo "$as_me:$LINENO: result: $hardcode_action" >&5
+echo "${ECHO_T}$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+striplib=
+old_striplib=
+{ echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+ ;;
+ *)
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ ;;
+ esac
+fi
+
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_dl_dlopen=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; }
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ { echo "$as_me:$LINENO: checking for shl_load" >&5
+echo $ECHO_N "checking for shl_load... $ECHO_C" >&6; }
+if test "${ac_cv_func_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shl_load (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_shl_load || defined __stub___shl_load
+choke me
+#endif
+
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_func_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_func_shl_load=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+echo "${ECHO_T}$ac_cv_func_shl_load" >&6; }
+if test $ac_cv_func_shl_load = yes; then
+ lt_cv_dlopen="shl_load"
+else
+ { echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_dld_shl_load=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6; }
+if test $ac_cv_lib_dld_shl_load = yes; then
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
+else
+ { echo "$as_me:$LINENO: checking for dlopen" >&5
+echo $ECHO_N "checking for dlopen... $ECHO_C" >&6; }
+if test "${ac_cv_func_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char dlopen (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_dlopen || defined __stub___dlopen
+choke me
+#endif
+
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_func_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_func_dlopen=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+echo "${ECHO_T}$ac_cv_func_dlopen" >&6; }
+if test $ac_cv_func_dlopen = yes; then
+ lt_cv_dlopen="dlopen"
+else
+ { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_dl_dlopen=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; }
+if test $ac_cv_lib_dl_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6; }
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_svld_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_svld_dlopen=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6; }
+if test $ac_cv_lib_svld_dlopen = yes; then
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_dld_dld_link=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_dld_dld_link=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6; }
+if test $ac_cv_lib_dld_dld_link = yes; then
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6; }
+if test "${lt_cv_dlopen_self+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 9405 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6; }
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<EOF
+#line 9505 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ exit (status);
+}
+EOF
+ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+# Report which library types will actually be built
+{ echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $can_build_shared" >&5
+echo "${ECHO_T}$can_build_shared" >&6; }
+
+{ echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6; }
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+aix4* | aix5*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+esac
+{ echo "$as_me:$LINENO: result: $enable_shared" >&5
+echo "${ECHO_T}$enable_shared" >&6; }
+
+{ echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6; }
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+{ echo "$as_me:$LINENO: result: $enable_static" >&5
+echo "${ECHO_T}$enable_static" >&6; }
+
+# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+ # See if we are running on zsh, and set the options which allow our commands through
+ # without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+ # Now quote all the things that may contain metacharacters while being
+ # careful not to overquote the AC_SUBSTed values. We take copies of the
+ # variables and quote the copies for generation of the libtool script.
+ for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
+ SED SHELL STRIP \
+ libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+ old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+ deplibs_check_method reload_flag reload_cmds need_locks \
+ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+ lt_cv_sys_global_symbol_to_c_name_address \
+ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+ old_postinstall_cmds old_postuninstall_cmds \
+ compiler \
+ CC \
+ LD \
+ lt_prog_compiler_wl \
+ lt_prog_compiler_pic \
+ lt_prog_compiler_static \
+ lt_prog_compiler_no_builtin_flag \
+ export_dynamic_flag_spec \
+ thread_safe_flag_spec \
+ whole_archive_flag_spec \
+ enable_shared_with_static_runtimes \
+ old_archive_cmds \
+ old_archive_from_new_cmds \
+ predep_objects \
+ postdep_objects \
+ predeps \
+ postdeps \
+ compiler_lib_search_path \
+ archive_cmds \
+ archive_expsym_cmds \
+ postinstall_cmds \
+ postuninstall_cmds \
+ old_archive_from_expsyms_cmds \
+ allow_undefined_flag \
+ no_undefined_flag \
+ export_symbols_cmds \
+ hardcode_libdir_flag_spec \
+ hardcode_libdir_flag_spec_ld \
+ hardcode_libdir_separator \
+ hardcode_automatic \
+ module_cmds \
+ module_expsym_cmds \
+ lt_cv_prog_compiler_c_o \
+ fix_srcfile_path \
+ exclude_expsyms \
+ include_expsyms; do
+
+ case $var in
+ old_archive_cmds | \
+ old_archive_from_new_cmds | \
+ archive_cmds | \
+ archive_expsym_cmds | \
+ module_cmds | \
+ module_expsym_cmds | \
+ old_archive_from_expsyms_cmds | \
+ export_symbols_cmds | \
+ extract_expsyms_cmds | reload_cmds | finish_cmds | \
+ postinstall_cmds | postuninstall_cmds | \
+ old_postinstall_cmds | old_postuninstall_cmds | \
+ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+ # Double-quote double-evaled strings.
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+ ;;
+ *)
+ eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+ ;;
+ esac
+ done
+
+ case $lt_echo in
+ *'\$0 --fallback-echo"')
+ lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
+ ;;
+ esac
+
+cfgfile="${ofile}T"
+ trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+ $rm -f "$cfgfile"
+ { echo "$as_me:$LINENO: creating $ofile" >&5
+echo "$as_me: creating $ofile" >&6;}
+
+ cat <<__EOF__ >> "$cfgfile"
+#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e 1s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
+# A language-specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU C compiler?
+with_gcc=$GCC
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_thread_safe_flag_spec
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_old_archive_cmds
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_predep_objects
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_postdep_objects
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_predeps
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$hardcode_automatic
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# ### END LIBTOOL CONFIG
+
+__EOF__
+
+
+ case $host_os in
+ aix3*)
+ cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+EOF
+ ;;
+ esac
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" || \
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+else
+ # If there is no Makefile yet, we rely on a make rule to execute
+ # `config.status --recheck' to rerun these tests and create the
+ # libtool script then.
+ ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+ if test -f "$ltmain_in"; then
+ test -f Makefile && make "$ltmain"
+ fi
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+# Prevent multiple expansion
+
+
+
+
+
+
+
+
+
+
+
+ { echo "$as_me:$LINENO: checking for ppoll" >&5
+echo $ECHO_N "checking for ppoll... $ECHO_C" >&6; }
+if test "${ac_cv_func_ppoll+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define ppoll to an innocuous variant, in case <limits.h> declares ppoll.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define ppoll innocuous_ppoll
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char ppoll (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef ppoll
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ppoll ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_ppoll || defined __stub___ppoll
+choke me
+#endif
+
+int
+main ()
+{
+return ppoll ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_func_ppoll=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_func_ppoll=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_ppoll" >&5
+echo "${ECHO_T}$ac_cv_func_ppoll" >&6; }
+if test $ac_cv_func_ppoll = yes; then
+ dummy=yes
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define NEED_PPOLL 1
+_ACEOF
+
+fi
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5
+echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5
+echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ PKG_CONFIG=""
+ fi
+
+fi
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for BLUEZ" >&5
+echo $ECHO_N "checking for BLUEZ... $ECHO_C" >&6; }
+
+if test -n "$BLUEZ_CFLAGS"; then
+ pkg_cv_BLUEZ_CFLAGS="$BLUEZ_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"bluez\"") >&5
+ ($PKG_CONFIG --exists --print-errors "bluez") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_BLUEZ_CFLAGS=`$PKG_CONFIG --cflags "bluez" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$BLUEZ_LIBS"; then
+ pkg_cv_BLUEZ_LIBS="$BLUEZ_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"bluez\"") >&5
+ ($PKG_CONFIG --exists --print-errors "bluez") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_BLUEZ_LIBS=`$PKG_CONFIG --libs "bluez" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ BLUEZ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "bluez" 2>&1`
+ else
+ BLUEZ_PKG_ERRORS=`$PKG_CONFIG --print-errors "bluez" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$BLUEZ_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ { { echo "$as_me:$LINENO: error: Bluetooth library is required" >&5
+echo "$as_me: error: Bluetooth library is required" >&2;}
+ { (exit 1); exit 1; }; }
+elif test $pkg_failed = untried; then
+ { { echo "$as_me:$LINENO: error: Bluetooth library is required" >&5
+echo "$as_me: error: Bluetooth library is required" >&2;}
+ { (exit 1); exit 1; }; }
+else
+ BLUEZ_CFLAGS=$pkg_cv_BLUEZ_CFLAGS
+ BLUEZ_LIBS=$pkg_cv_BLUEZ_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ dummy=yes
+fi
+
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for GLIB" >&5
+echo $ECHO_N "checking for GLIB... $ECHO_C" >&6; }
+
+if test -n "$GLIB_CFLAGS"; then
+ pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"glib-2.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "glib-2.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$GLIB_LIBS"; then
+ pkg_cv_GLIB_LIBS="$GLIB_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"glib-2.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "glib-2.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "glib-2.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "glib-2.0" 2>&1`
+ else
+ GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors "glib-2.0" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GLIB_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ glib_found=no
+elif test $pkg_failed = untried; then
+ glib_found=no
+else
+ GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS
+ GLIB_LIBS=$pkg_cv_GLIB_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ glib_found=yes
+fi
+
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for GMODULE" >&5
+echo $ECHO_N "checking for GMODULE... $ECHO_C" >&6; }
+
+if test -n "$GMODULE_CFLAGS"; then
+ pkg_cv_GMODULE_CFLAGS="$GMODULE_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gmodule-2.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gmodule-2.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GMODULE_CFLAGS=`$PKG_CONFIG --cflags "gmodule-2.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$GMODULE_LIBS"; then
+ pkg_cv_GMODULE_LIBS="$GMODULE_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gmodule-2.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gmodule-2.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GMODULE_LIBS=`$PKG_CONFIG --libs "gmodule-2.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GMODULE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "gmodule-2.0" 2>&1`
+ else
+ GMODULE_PKG_ERRORS=`$PKG_CONFIG --print-errors "gmodule-2.0" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GMODULE_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ gmodule_found=no
+elif test $pkg_failed = untried; then
+ gmodule_found=no
+else
+ GMODULE_CFLAGS=$pkg_cv_GMODULE_CFLAGS
+ GMODULE_LIBS=$pkg_cv_GMODULE_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ gmodule_found=yes
+fi
+ { echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_dl_dlopen=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; }
+if test $ac_cv_lib_dl_dlopen = yes; then
+ dummy=yes
+else
+ dummy=no
+fi
+
+
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for DBUS" >&5
+echo $ECHO_N "checking for DBUS... $ECHO_C" >&6; }
+
+if test -n "$DBUS_CFLAGS"; then
+ pkg_cv_DBUS_CFLAGS="$DBUS_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_DBUS_CFLAGS=`$PKG_CONFIG --cflags "dbus-1 >= 1.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$DBUS_LIBS"; then
+ pkg_cv_DBUS_LIBS="$DBUS_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_DBUS_LIBS=`$PKG_CONFIG --libs "dbus-1 >= 1.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ DBUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "dbus-1 >= 1.0" 2>&1`
+ else
+ DBUS_PKG_ERRORS=`$PKG_CONFIG --print-errors "dbus-1 >= 1.0" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$DBUS_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ { { echo "$as_me:$LINENO: error: D-Bus library is required" >&5
+echo "$as_me: error: D-Bus library is required" >&2;}
+ { (exit 1); exit 1; }; }
+elif test $pkg_failed = untried; then
+ { { echo "$as_me:$LINENO: error: D-Bus library is required" >&5
+echo "$as_me: error: D-Bus library is required" >&2;}
+ { (exit 1); exit 1; }; }
+else
+ DBUS_CFLAGS=$pkg_cv_DBUS_CFLAGS
+ DBUS_LIBS=$pkg_cv_DBUS_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ dummy=yes
+fi
+ { echo "$as_me:$LINENO: checking for dbus_watch_get_unix_fd in -ldbus-1" >&5
+echo $ECHO_N "checking for dbus_watch_get_unix_fd in -ldbus-1... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dbus_1_dbus_watch_get_unix_fd+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldbus-1 $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dbus_watch_get_unix_fd ();
+int
+main ()
+{
+return dbus_watch_get_unix_fd ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_dbus_1_dbus_watch_get_unix_fd=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_dbus_1_dbus_watch_get_unix_fd=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dbus_1_dbus_watch_get_unix_fd" >&5
+echo "${ECHO_T}$ac_cv_lib_dbus_1_dbus_watch_get_unix_fd" >&6; }
+if test $ac_cv_lib_dbus_1_dbus_watch_get_unix_fd = yes; then
+ dummy=yes
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define NEED_DBUS_WATCH_GET_UNIX_FD 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for ALSA" >&5
+echo $ECHO_N "checking for ALSA... $ECHO_C" >&6; }
+
+if test -n "$ALSA_CFLAGS"; then
+ pkg_cv_ALSA_CFLAGS="$ALSA_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"alsa\"") >&5
+ ($PKG_CONFIG --exists --print-errors "alsa") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_ALSA_CFLAGS=`$PKG_CONFIG --cflags "alsa" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$ALSA_LIBS"; then
+ pkg_cv_ALSA_LIBS="$ALSA_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"alsa\"") >&5
+ ($PKG_CONFIG --exists --print-errors "alsa") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_ALSA_LIBS=`$PKG_CONFIG --libs "alsa" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ ALSA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "alsa" 2>&1`
+ else
+ ALSA_PKG_ERRORS=`$PKG_CONFIG --print-errors "alsa" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$ALSA_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ alsa_found=no
+elif test $pkg_failed = untried; then
+ alsa_found=no
+else
+ ALSA_CFLAGS=$pkg_cv_ALSA_CFLAGS
+ ALSA_LIBS=$pkg_cv_ALSA_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ alsa_found=yes
+fi
+ { echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
+echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6; }
+if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_rt_clock_gettime=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_rt_clock_gettime=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_rt_clock_gettime" >&5
+echo "${ECHO_T}$ac_cv_lib_rt_clock_gettime" >&6; }
+if test $ac_cv_lib_rt_clock_gettime = yes; then
+ ALSA_LIBS="$ALSA_LIBS -lrt"
+else
+ alsa_found=no
+fi
+
+
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for GSTREAMER" >&5
+echo $ECHO_N "checking for GSTREAMER... $ECHO_C" >&6; }
+
+if test -n "$GSTREAMER_CFLAGS"; then
+ pkg_cv_GSTREAMER_CFLAGS="$GSTREAMER_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gstreamer-0.10 gstreamer-plugins-base-0.10\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gstreamer-0.10 gstreamer-plugins-base-0.10") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GSTREAMER_CFLAGS=`$PKG_CONFIG --cflags "gstreamer-0.10 gstreamer-plugins-base-0.10" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$GSTREAMER_LIBS"; then
+ pkg_cv_GSTREAMER_LIBS="$GSTREAMER_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gstreamer-0.10 gstreamer-plugins-base-0.10\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gstreamer-0.10 gstreamer-plugins-base-0.10") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GSTREAMER_LIBS=`$PKG_CONFIG --libs "gstreamer-0.10 gstreamer-plugins-base-0.10" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GSTREAMER_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "gstreamer-0.10 gstreamer-plugins-base-0.10" 2>&1`
+ else
+ GSTREAMER_PKG_ERRORS=`$PKG_CONFIG --print-errors "gstreamer-0.10 gstreamer-plugins-base-0.10" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GSTREAMER_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ gstreamer_found=no
+elif test $pkg_failed = untried; then
+ gstreamer_found=no
+else
+ GSTREAMER_CFLAGS=$pkg_cv_GSTREAMER_CFLAGS
+ GSTREAMER_LIBS=$pkg_cv_GSTREAMER_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ gstreamer_found=yes
+fi
+
+
+ GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10`
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for USB" >&5
+echo $ECHO_N "checking for USB... $ECHO_C" >&6; }
+
+if test -n "$USB_CFLAGS"; then
+ pkg_cv_USB_CFLAGS="$USB_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libusb\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libusb") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_USB_CFLAGS=`$PKG_CONFIG --cflags "libusb" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$USB_LIBS"; then
+ pkg_cv_USB_LIBS="$USB_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libusb\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libusb") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_USB_LIBS=`$PKG_CONFIG --libs "libusb" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ USB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libusb" 2>&1`
+ else
+ USB_PKG_ERRORS=`$PKG_CONFIG --print-errors "libusb" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$USB_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ usb_found=no
+elif test $pkg_failed = untried; then
+ usb_found=no
+else
+ USB_CFLAGS=$pkg_cv_USB_CFLAGS
+ USB_LIBS=$pkg_cv_USB_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ usb_found=yes
+fi
+
+
+ { echo "$as_me:$LINENO: checking for usb_get_busses in -lusb" >&5
+echo $ECHO_N "checking for usb_get_busses in -lusb... $ECHO_C" >&6; }
+if test "${ac_cv_lib_usb_usb_get_busses+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lusb $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char usb_get_busses ();
+int
+main ()
+{
+return usb_get_busses ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_usb_usb_get_busses=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_usb_usb_get_busses=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_usb_usb_get_busses" >&5
+echo "${ECHO_T}$ac_cv_lib_usb_usb_get_busses" >&6; }
+if test $ac_cv_lib_usb_usb_get_busses = yes; then
+ dummy=yes
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define NEED_USB_GET_BUSSES 1
+_ACEOF
+
+fi
+
+ { echo "$as_me:$LINENO: checking for usb_interrupt_read in -lusb" >&5
+echo $ECHO_N "checking for usb_interrupt_read in -lusb... $ECHO_C" >&6; }
+if test "${ac_cv_lib_usb_usb_interrupt_read+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lusb $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char usb_interrupt_read ();
+int
+main ()
+{
+return usb_interrupt_read ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_usb_usb_interrupt_read=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_usb_usb_interrupt_read=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_usb_usb_interrupt_read" >&5
+echo "${ECHO_T}$ac_cv_lib_usb_usb_interrupt_read" >&6; }
+if test $ac_cv_lib_usb_usb_interrupt_read = yes; then
+ dummy=yes
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define NEED_USB_INTERRUPT_READ 1
+_ACEOF
+
+fi
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for NETLINK" >&5
+echo $ECHO_N "checking for NETLINK... $ECHO_C" >&6; }
+
+if test -n "$NETLINK_CFLAGS"; then
+ pkg_cv_NETLINK_CFLAGS="$NETLINK_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libnl-1\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libnl-1") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_NETLINK_CFLAGS=`$PKG_CONFIG --cflags "libnl-1" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$NETLINK_LIBS"; then
+ pkg_cv_NETLINK_LIBS="$NETLINK_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libnl-1\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libnl-1") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_NETLINK_LIBS=`$PKG_CONFIG --libs "libnl-1" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ NETLINK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libnl-1" 2>&1`
+ else
+ NETLINK_PKG_ERRORS=`$PKG_CONFIG --print-errors "libnl-1" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$NETLINK_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ netlink_found=no
+elif test $pkg_failed = untried; then
+ netlink_found=no
+else
+ NETLINK_CFLAGS=$pkg_cv_NETLINK_CFLAGS
+ NETLINK_LIBS=$pkg_cv_NETLINK_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ netlink_found=yes
+fi
+
+
+
+
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for SNDFILE" >&5
+echo $ECHO_N "checking for SNDFILE... $ECHO_C" >&6; }
+
+if test -n "$SNDFILE_CFLAGS"; then
+ pkg_cv_SNDFILE_CFLAGS="$SNDFILE_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sndfile\"") >&5
+ ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_SNDFILE_CFLAGS=`$PKG_CONFIG --cflags "sndfile" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$SNDFILE_LIBS"; then
+ pkg_cv_SNDFILE_LIBS="$SNDFILE_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sndfile\"") >&5
+ ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_SNDFILE_LIBS=`$PKG_CONFIG --libs "sndfile" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ SNDFILE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "sndfile" 2>&1`
+ else
+ SNDFILE_PKG_ERRORS=`$PKG_CONFIG --print-errors "sndfile" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$SNDFILE_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ sndfile_found=no
+elif test $pkg_failed = untried; then
+ sndfile_found=no
+else
+ SNDFILE_CFLAGS=$pkg_cv_SNDFILE_CFLAGS
+ SNDFILE_LIBS=$pkg_cv_SNDFILE_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ sndfile_found=yes
+fi
+
+
+
+
+
+ debug_enable=no
+ fortify_enable=yes
+ pie_enable=yes
+ sndfile_enable=${sndfile_found}
+ netlink_enable=no
+ usb_enable=${usb_found}
+ alsa_enable=${alsa_found}
+ glib_enable=yes
+ gstreamer_enable=${gstreamer_found}
+ audio_enable=yes
+ input_enable=yes
+ serial_enable=yes
+ network_enable=yes
+ tools_enable=yes
+ hidd_enable=no
+ pand_enable=no
+ dund_enable=no
+ cups_enable=no
+ test_enable=no
+ bccmd_enable=no
+ hid2hci_enable=no
+ dfutool_enable=no
+ manpages_enable=yes
+ configfiles_enable=yes
+ initscripts_enable=no
+ pcmciarules_enable=no
+
+ # Check whether --enable-fortify was given.
+if test "${enable_fortify+set}" = set; then
+ enableval=$enable_fortify;
+ fortify_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-pie was given.
+if test "${enable_pie+set}" = set; then
+ enableval=$enable_pie;
+ pie_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-glib was given.
+if test "${enable_glib+set}" = set; then
+ enableval=$enable_glib;
+ glib_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-network was given.
+if test "${enable_network+set}" = set; then
+ enableval=$enable_network;
+ network_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-serial was given.
+if test "${enable_serial+set}" = set; then
+ enableval=$enable_serial;
+ serial_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-input was given.
+if test "${enable_input+set}" = set; then
+ enableval=$enable_input;
+ input_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-audio was given.
+if test "${enable_audio+set}" = set; then
+ enableval=$enable_audio;
+ audio_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-gstreamer was given.
+if test "${enable_gstreamer+set}" = set; then
+ enableval=$enable_gstreamer;
+ gstreamer_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-alsa was given.
+if test "${enable_alsa+set}" = set; then
+ enableval=$enable_alsa;
+ alsa_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-usb was given.
+if test "${enable_usb+set}" = set; then
+ enableval=$enable_usb;
+ usb_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-netlink was given.
+if test "${enable_netlink+set}" = set; then
+ enableval=$enable_netlink;
+ netlink_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-tools was given.
+if test "${enable_tools+set}" = set; then
+ enableval=$enable_tools;
+ tools_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-bccmd was given.
+if test "${enable_bccmd+set}" = set; then
+ enableval=$enable_bccmd;
+ bccmd_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-hid2hci was given.
+if test "${enable_hid2hci+set}" = set; then
+ enableval=$enable_hid2hci;
+ hid2hci_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-dfutool was given.
+if test "${enable_dfutool+set}" = set; then
+ enableval=$enable_dfutool;
+ dfutool_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-hidd was given.
+if test "${enable_hidd+set}" = set; then
+ enableval=$enable_hidd;
+ hidd_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-pand was given.
+if test "${enable_pand+set}" = set; then
+ enableval=$enable_pand;
+ pand_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-dund was given.
+if test "${enable_dund+set}" = set; then
+ enableval=$enable_dund;
+ dund_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-cups was given.
+if test "${enable_cups+set}" = set; then
+ enableval=$enable_cups;
+ cups_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-test was given.
+if test "${enable_test+set}" = set; then
+ enableval=$enable_test;
+ test_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-manpages was given.
+if test "${enable_manpages+set}" = set; then
+ enableval=$enable_manpages;
+ manpages_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-configfiles was given.
+if test "${enable_configfiles+set}" = set; then
+ enableval=$enable_configfiles;
+ configfiles_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-initscripts was given.
+if test "${enable_initscripts+set}" = set; then
+ enableval=$enable_initscripts;
+ initscripts_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-pcmciarules was given.
+if test "${enable_pcmciarules+set}" = set; then
+ enableval=$enable_pcmciarules;
+ pcmciarules_enable=${enableval}
+
+fi
+
+
+ # Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then
+ enableval=$enable_debug;
+ debug_enable=${enableval}
+
+fi
+
+
+ if (test "${fortify_enable}" = "yes"); then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
+ fi
+
+ if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then
+ CFLAGS="$CFLAGS -fPIE"
+ LDFLAGS="$LDFLAGS -pie"
+ fi
+
+ if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then
+ CFLAGS="$CFLAGS -g -O0"
+ fi
+
+ if (test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"); then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBUSB 1
+_ACEOF
+
+ fi
+
+ if (test "${glib_enable}" = "yes" && test "${glib_found}" = "yes"); then
+ if true; then
+ GLIB_TRUE=
+ GLIB_FALSE='#'
+else
+ GLIB_TRUE='#'
+ GLIB_FALSE=
+fi
+
+ else
+ GLIB_CFLAGS='-I$(top_srcdir)/eglib'
+
+ GLIB_LIBS='$(top_builddir)/eglib/libeglib.la -ldl -rdynamic'
+
+ GMODULE_CFLAGS=''
+
+ GMODULE_LIBS=''
+
+ if false; then
+ GLIB_TRUE=
+ GLIB_FALSE='#'
+else
+ GLIB_TRUE='#'
+ GLIB_FALSE=
+fi
+
+ fi
+
+ GDBUS_CFLAGS='-I$(top_srcdir)/gdbus'
+
+ GDBUS_LIBS='$(top_builddir)/gdbus/libgdbus.la'
+
+
+ SBC_CFLAGS='-I$(top_srcdir)/sbc'
+
+ SBC_LIBS='$(top_builddir)/sbc/libsbc.la'
+
+
+ if test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes"; then
+ SNDFILE_TRUE=
+ SNDFILE_FALSE='#'
+else
+ SNDFILE_TRUE='#'
+ SNDFILE_FALSE=
+fi
+
+ if test "${netlink_enable}" = "yes" && test "${netlink_found}" = "yes"; then
+ NETLINK_TRUE=
+ NETLINK_FALSE='#'
+else
+ NETLINK_TRUE='#'
+ NETLINK_FALSE=
+fi
+
+ if test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"; then
+ USB_TRUE=
+ USB_FALSE='#'
+else
+ USB_TRUE='#'
+ USB_FALSE=
+fi
+
+ if test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes"; then
+ SBC_TRUE=
+ SBC_FALSE='#'
+else
+ SBC_TRUE='#'
+ SBC_FALSE=
+fi
+
+ if test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes"; then
+ ALSA_TRUE=
+ ALSA_FALSE='#'
+else
+ ALSA_TRUE='#'
+ ALSA_FALSE=
+fi
+
+ if test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes"; then
+ GSTREAMER_TRUE=
+ GSTREAMER_FALSE='#'
+else
+ GSTREAMER_TRUE='#'
+ GSTREAMER_FALSE=
+fi
+
+ if test "${audio_enable}" = "yes"; then
+ AUDIOPLUGIN_TRUE=
+ AUDIOPLUGIN_FALSE='#'
+else
+ AUDIOPLUGIN_TRUE='#'
+ AUDIOPLUGIN_FALSE=
+fi
+
+ if test "${input_enable}" = "yes"; then
+ INPUTPLUGIN_TRUE=
+ INPUTPLUGIN_FALSE='#'
+else
+ INPUTPLUGIN_TRUE='#'
+ INPUTPLUGIN_FALSE=
+fi
+
+ if test "${serial_enable}" = "yes"; then
+ SERIALPLUGIN_TRUE=
+ SERIALPLUGIN_FALSE='#'
+else
+ SERIALPLUGIN_TRUE='#'
+ SERIALPLUGIN_FALSE=
+fi
+
+ if test "${network_enable}" = "yes"; then
+ NETWORKPLUGIN_TRUE=
+ NETWORKPLUGIN_FALSE='#'
+else
+ NETWORKPLUGIN_TRUE='#'
+ NETWORKPLUGIN_FALSE=
+fi
+
+ if test "${hidd_enable}" = "yes"; then
+ HIDD_TRUE=
+ HIDD_FALSE='#'
+else
+ HIDD_TRUE='#'
+ HIDD_FALSE=
+fi
+
+ if test "${pand_enable}" = "yes"; then
+ PAND_TRUE=
+ PAND_FALSE='#'
+else
+ PAND_TRUE='#'
+ PAND_FALSE=
+fi
+
+ if test "${dund_enable}" = "yes"; then
+ DUND_TRUE=
+ DUND_FALSE='#'
+else
+ DUND_TRUE='#'
+ DUND_FALSE=
+fi
+
+ if test "${cups_enable}" = "yes"; then
+ CUPS_TRUE=
+ CUPS_FALSE='#'
+else
+ CUPS_TRUE='#'
+ CUPS_FALSE=
+fi
+
+ if test "${test_enable}" = "yes"; then
+ TEST_TRUE=
+ TEST_FALSE='#'
+else
+ TEST_TRUE='#'
+ TEST_FALSE=
+fi
+
+ if test "${tools_enable}" = "yes"; then
+ TOOLS_TRUE=
+ TOOLS_FALSE='#'
+else
+ TOOLS_TRUE='#'
+ TOOLS_FALSE=
+fi
+
+ if test "${bccmd_enable}" = "yes"; then
+ BCCMD_TRUE=
+ BCCMD_FALSE='#'
+else
+ BCCMD_TRUE='#'
+ BCCMD_FALSE=
+fi
+
+ if test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes"; then
+ HID2HCI_TRUE=
+ HID2HCI_FALSE='#'
+else
+ HID2HCI_TRUE='#'
+ HID2HCI_FALSE=
+fi
+
+ if test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes"; then
+ DFUTOOL_TRUE=
+ DFUTOOL_FALSE='#'
+else
+ DFUTOOL_TRUE='#'
+ DFUTOOL_FALSE=
+fi
+
+ if test "${manpages_enable}" = "yes"; then
+ MANPAGES_TRUE=
+ MANPAGES_FALSE='#'
+else
+ MANPAGES_TRUE='#'
+ MANPAGES_FALSE=
+fi
+
+ if test "${configfiles_enable}" = "yes"; then
+ CONFIGFILES_TRUE=
+ CONFIGFILES_FALSE='#'
+else
+ CONFIGFILES_TRUE='#'
+ CONFIGFILES_FALSE=
+fi
+
+ if test "${initscripts_enable}" = "yes"; then
+ INITSCRIPTS_TRUE=
+ INITSCRIPTS_FALSE='#'
+else
+ INITSCRIPTS_TRUE='#'
+ INITSCRIPTS_FALSE=
+fi
+
+ if test "${pcmciarules_enable}" = "yes"; then
+ PCMCIARULES_TRUE=
+ PCMCIARULES_FALSE='#'
+else
+ PCMCIARULES_TRUE='#'
+ PCMCIARULES_FALSE=
+fi
+
+
+
+ac_config_files="$ac_config_files Makefile doc/Makefile sbc/Makefile eglib/Makefile gdbus/Makefile common/Makefile plugins/Makefile network/Makefile serial/Makefile input/Makefile audio/Makefile tools/Makefile rfcomm/Makefile hcid/Makefile sdpd/Makefile dund/Makefile pand/Makefile hidd/Makefile cups/Makefile test/Makefile scripts/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ *) $as_unset $ac_var ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${GLIB_TRUE}" && test -z "${GLIB_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${GLIB_TRUE}" && test -z "${GLIB_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"GLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${SNDFILE_TRUE}" && test -z "${SNDFILE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"SNDFILE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"SNDFILE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${NETLINK_TRUE}" && test -z "${NETLINK_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"NETLINK\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"NETLINK\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${USB_TRUE}" && test -z "${USB_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"USB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"USB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${SBC_TRUE}" && test -z "${SBC_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"SBC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"SBC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${ALSA_TRUE}" && test -z "${ALSA_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"ALSA\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"ALSA\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${GSTREAMER_TRUE}" && test -z "${GSTREAMER_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"GSTREAMER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"GSTREAMER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${AUDIOPLUGIN_TRUE}" && test -z "${AUDIOPLUGIN_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"AUDIOPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"AUDIOPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${INPUTPLUGIN_TRUE}" && test -z "${INPUTPLUGIN_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"INPUTPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"INPUTPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${SERIALPLUGIN_TRUE}" && test -z "${SERIALPLUGIN_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"SERIALPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"SERIALPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${NETWORKPLUGIN_TRUE}" && test -z "${NETWORKPLUGIN_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"NETWORKPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"NETWORKPLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${HIDD_TRUE}" && test -z "${HIDD_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HIDD\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HIDD\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${PAND_TRUE}" && test -z "${PAND_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"PAND\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"PAND\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${DUND_TRUE}" && test -z "${DUND_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"DUND\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"DUND\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${CUPS_TRUE}" && test -z "${CUPS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"CUPS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"CUPS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${TEST_TRUE}" && test -z "${TEST_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"TEST\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"TEST\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${TOOLS_TRUE}" && test -z "${TOOLS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"TOOLS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"TOOLS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${BCCMD_TRUE}" && test -z "${BCCMD_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"BCCMD\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"BCCMD\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${HID2HCI_TRUE}" && test -z "${HID2HCI_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HID2HCI\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HID2HCI\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${DFUTOOL_TRUE}" && test -z "${DFUTOOL_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"DFUTOOL\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"DFUTOOL\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${MANPAGES_TRUE}" && test -z "${MANPAGES_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MANPAGES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MANPAGES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${CONFIGFILES_TRUE}" && test -z "${CONFIGFILES_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"CONFIGFILES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"CONFIGFILES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${INITSCRIPTS_TRUE}" && test -z "${INITSCRIPTS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"INITSCRIPTS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"INITSCRIPTS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${PCMCIARULES_TRUE}" && test -z "${PCMCIARULES_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"PCMCIARULES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"PCMCIARULES\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. Blame Lee
+ # E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.61. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.61,
+ with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ echo "$ac_cs_version"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ CONFIG_SHELL=$SHELL
+ export CONFIG_SHELL
+ exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "sbc/Makefile") CONFIG_FILES="$CONFIG_FILES sbc/Makefile" ;;
+ "eglib/Makefile") CONFIG_FILES="$CONFIG_FILES eglib/Makefile" ;;
+ "gdbus/Makefile") CONFIG_FILES="$CONFIG_FILES gdbus/Makefile" ;;
+ "common/Makefile") CONFIG_FILES="$CONFIG_FILES common/Makefile" ;;
+ "plugins/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/Makefile" ;;
+ "network/Makefile") CONFIG_FILES="$CONFIG_FILES network/Makefile" ;;
+ "serial/Makefile") CONFIG_FILES="$CONFIG_FILES serial/Makefile" ;;
+ "input/Makefile") CONFIG_FILES="$CONFIG_FILES input/Makefile" ;;
+ "audio/Makefile") CONFIG_FILES="$CONFIG_FILES audio/Makefile" ;;
+ "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
+ "rfcomm/Makefile") CONFIG_FILES="$CONFIG_FILES rfcomm/Makefile" ;;
+ "hcid/Makefile") CONFIG_FILES="$CONFIG_FILES hcid/Makefile" ;;
+ "sdpd/Makefile") CONFIG_FILES="$CONFIG_FILES sdpd/Makefile" ;;
+ "dund/Makefile") CONFIG_FILES="$CONFIG_FILES dund/Makefile" ;;
+ "pand/Makefile") CONFIG_FILES="$CONFIG_FILES pand/Makefile" ;;
+ "hidd/Makefile") CONFIG_FILES="$CONFIG_FILES hidd/Makefile" ;;
+ "cups/Makefile") CONFIG_FILES="$CONFIG_FILES cups/Makefile" ;;
+ "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
+ "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
+
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp=
+ trap 'exit_status=$?
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+am__isrc!$am__isrc$ac_delim
+CYGPATH_W!$CYGPATH_W$ac_delim
+PACKAGE!$PACKAGE$ac_delim
+VERSION!$VERSION$ac_delim
+ACLOCAL!$ACLOCAL$ac_delim
+AUTOCONF!$AUTOCONF$ac_delim
+AUTOMAKE!$AUTOMAKE$ac_delim
+AUTOHEADER!$AUTOHEADER$ac_delim
+MAKEINFO!$MAKEINFO$ac_delim
+install_sh!$install_sh$ac_delim
+STRIP!$STRIP$ac_delim
+INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim
+mkdir_p!$mkdir_p$ac_delim
+AWK!$AWK$ac_delim
+SET_MAKE!$SET_MAKE$ac_delim
+am__leading_dot!$am__leading_dot$ac_delim
+AMTAR!$AMTAR$ac_delim
+am__tar!$am__tar$ac_delim
+am__untar!$am__untar$ac_delim
+MAINTAINER_MODE_TRUE!$MAINTAINER_MODE_TRUE$ac_delim
+MAINTAINER_MODE_FALSE!$MAINTAINER_MODE_FALSE$ac_delim
+MAINT!$MAINT$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+DEPDIR!$DEPDIR$ac_delim
+am__include!$am__include$ac_delim
+am__quote!$am__quote$ac_delim
+AMDEP_TRUE!$AMDEP_TRUE$ac_delim
+AMDEP_FALSE!$AMDEP_FALSE$ac_delim
+AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim
+CCDEPMODE!$CCDEPMODE$ac_delim
+am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim
+am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim
+YACC!$YACC$ac_delim
+YFLAGS!$YFLAGS$ac_delim
+LEX!$LEX$ac_delim
+LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim
+LEXLIB!$LEXLIB$ac_delim
+build!$build$ac_delim
+build_cpu!$build_cpu$ac_delim
+build_vendor!$build_vendor$ac_delim
+build_os!$build_os$ac_delim
+host!$host$ac_delim
+host_cpu!$host_cpu$ac_delim
+host_vendor!$host_vendor$ac_delim
+host_os!$host_os$ac_delim
+SED!$SED$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+LN_S!$LN_S$ac_delim
+ECHO!$ECHO$ac_delim
+AR!$AR$ac_delim
+_ACEOF
+
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
+ break
+ elif $ac_last_try; then
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+ ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+ ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+CEOF$ac_eof
+_ACEOF
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ cat >conf$$subs.sed <<_ACEOF
+RANLIB!$RANLIB$ac_delim
+CPP!$CPP$ac_delim
+LIBTOOL!$LIBTOOL$ac_delim
+PKG_CONFIG!$PKG_CONFIG$ac_delim
+BLUEZ_CFLAGS!$BLUEZ_CFLAGS$ac_delim
+BLUEZ_LIBS!$BLUEZ_LIBS$ac_delim
+GLIB_CFLAGS!$GLIB_CFLAGS$ac_delim
+GLIB_LIBS!$GLIB_LIBS$ac_delim
+GMODULE_CFLAGS!$GMODULE_CFLAGS$ac_delim
+GMODULE_LIBS!$GMODULE_LIBS$ac_delim
+DBUS_CFLAGS!$DBUS_CFLAGS$ac_delim
+DBUS_LIBS!$DBUS_LIBS$ac_delim
+ALSA_CFLAGS!$ALSA_CFLAGS$ac_delim
+ALSA_LIBS!$ALSA_LIBS$ac_delim
+GSTREAMER_CFLAGS!$GSTREAMER_CFLAGS$ac_delim
+GSTREAMER_LIBS!$GSTREAMER_LIBS$ac_delim
+GSTREAMER_PLUGINSDIR!$GSTREAMER_PLUGINSDIR$ac_delim
+USB_CFLAGS!$USB_CFLAGS$ac_delim
+USB_LIBS!$USB_LIBS$ac_delim
+NETLINK_CFLAGS!$NETLINK_CFLAGS$ac_delim
+NETLINK_LIBS!$NETLINK_LIBS$ac_delim
+SNDFILE_CFLAGS!$SNDFILE_CFLAGS$ac_delim
+SNDFILE_LIBS!$SNDFILE_LIBS$ac_delim
+GLIB_TRUE!$GLIB_TRUE$ac_delim
+GLIB_FALSE!$GLIB_FALSE$ac_delim
+GDBUS_CFLAGS!$GDBUS_CFLAGS$ac_delim
+GDBUS_LIBS!$GDBUS_LIBS$ac_delim
+SBC_CFLAGS!$SBC_CFLAGS$ac_delim
+SBC_LIBS!$SBC_LIBS$ac_delim
+SNDFILE_TRUE!$SNDFILE_TRUE$ac_delim
+SNDFILE_FALSE!$SNDFILE_FALSE$ac_delim
+NETLINK_TRUE!$NETLINK_TRUE$ac_delim
+NETLINK_FALSE!$NETLINK_FALSE$ac_delim
+USB_TRUE!$USB_TRUE$ac_delim
+USB_FALSE!$USB_FALSE$ac_delim
+SBC_TRUE!$SBC_TRUE$ac_delim
+SBC_FALSE!$SBC_FALSE$ac_delim
+ALSA_TRUE!$ALSA_TRUE$ac_delim
+ALSA_FALSE!$ALSA_FALSE$ac_delim
+GSTREAMER_TRUE!$GSTREAMER_TRUE$ac_delim
+GSTREAMER_FALSE!$GSTREAMER_FALSE$ac_delim
+AUDIOPLUGIN_TRUE!$AUDIOPLUGIN_TRUE$ac_delim
+AUDIOPLUGIN_FALSE!$AUDIOPLUGIN_FALSE$ac_delim
+INPUTPLUGIN_TRUE!$INPUTPLUGIN_TRUE$ac_delim
+INPUTPLUGIN_FALSE!$INPUTPLUGIN_FALSE$ac_delim
+SERIALPLUGIN_TRUE!$SERIALPLUGIN_TRUE$ac_delim
+SERIALPLUGIN_FALSE!$SERIALPLUGIN_FALSE$ac_delim
+NETWORKPLUGIN_TRUE!$NETWORKPLUGIN_TRUE$ac_delim
+NETWORKPLUGIN_FALSE!$NETWORKPLUGIN_FALSE$ac_delim
+HIDD_TRUE!$HIDD_TRUE$ac_delim
+HIDD_FALSE!$HIDD_FALSE$ac_delim
+PAND_TRUE!$PAND_TRUE$ac_delim
+PAND_FALSE!$PAND_FALSE$ac_delim
+DUND_TRUE!$DUND_TRUE$ac_delim
+DUND_FALSE!$DUND_FALSE$ac_delim
+CUPS_TRUE!$CUPS_TRUE$ac_delim
+CUPS_FALSE!$CUPS_FALSE$ac_delim
+TEST_TRUE!$TEST_TRUE$ac_delim
+TEST_FALSE!$TEST_FALSE$ac_delim
+TOOLS_TRUE!$TOOLS_TRUE$ac_delim
+TOOLS_FALSE!$TOOLS_FALSE$ac_delim
+BCCMD_TRUE!$BCCMD_TRUE$ac_delim
+BCCMD_FALSE!$BCCMD_FALSE$ac_delim
+HID2HCI_TRUE!$HID2HCI_TRUE$ac_delim
+HID2HCI_FALSE!$HID2HCI_FALSE$ac_delim
+DFUTOOL_TRUE!$DFUTOOL_TRUE$ac_delim
+DFUTOOL_FALSE!$DFUTOOL_FALSE$ac_delim
+MANPAGES_TRUE!$MANPAGES_TRUE$ac_delim
+MANPAGES_FALSE!$MANPAGES_FALSE$ac_delim
+CONFIGFILES_TRUE!$CONFIGFILES_TRUE$ac_delim
+CONFIGFILES_FALSE!$CONFIGFILES_FALSE$ac_delim
+INITSCRIPTS_TRUE!$INITSCRIPTS_TRUE$ac_delim
+INITSCRIPTS_FALSE!$INITSCRIPTS_FALSE$ac_delim
+PCMCIARULES_TRUE!$PCMCIARULES_TRUE$ac_delim
+PCMCIARULES_FALSE!$PCMCIARULES_FALSE$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 77; then
+ break
+ elif $ac_last_try; then
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+ ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+ ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[ ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+ { (exit 1); exit 1; }; };;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+ ac_file_inputs="$ac_file_inputs $ac_f"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input="Generated from "`IFS=:
+ echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ fi
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin";;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ { as_dir="$ac_dir"
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+ { (exit 1); exit 1; }; }; }
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out"; rm -f "$tmp/out";;
+ *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+ esac
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status. If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless. But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*'
+ac_dB='\\)[ (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+ sed -n '
+ t rset
+ :rset
+ s/^[ ]*#[ ]*define[ ][ ]*//
+ t ok
+ d
+ :ok
+ s/[\\&,]/\\&/g
+ s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+ s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+ ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then replace #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[ #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+ # Write a here document:
+ cat >>$CONFIG_STATUS <<_ACEOF
+ # First, check the format of the line:
+ cat >"\$tmp/defines.sed" <<\\CEOF
+/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def
+/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def
+b
+:def
+_ACEOF
+ sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+ ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+ sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+ grep . conftest.tail >/dev/null || break
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+ if test x"$ac_file" != x-; then
+ echo "/* $configure_input */" >"$tmp/config.h"
+ cat "$ac_result" >>"$tmp/config.h"
+ if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f $ac_file
+ mv "$tmp/config.h" $ac_file
+ fi
+ else
+ echo "/* $configure_input */"
+ cat "$ac_result"
+ fi
+ rm -f "$tmp/out12"
+# Compute $ac_file's index in $config_headers.
+_am_arg=$ac_file
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5
+echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ { as_dir=$dirpart/$fdir
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+ { (exit 1); exit 1; }; }; }
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+ ;;
+
+ esac
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/utils/configure.in b/utils/configure.in
new file mode 100644
index 00000000..6577c7f7
--- /dev/null
+++ b/utils/configure.in
@@ -0,0 +1,61 @@
+AC_PREREQ(2.50)
+AC_INIT()
+
+AM_INIT_AUTOMAKE(bluez-utils, 3.35)
+AM_CONFIG_HEADER(config.h)
+
+AM_MAINTAINER_MODE
+
+AC_INIT_BLUEZ
+
+AC_LANG_C
+
+AC_PROG_CC
+AC_PROG_CC_PIE
+AC_PROG_INSTALL
+AC_PROG_YACC
+AM_PROG_LEX
+
+m4_define([_LT_AC_TAGCONFIG], [])
+m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
+
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+AC_FUNC_PPOLL
+
+AC_PATH_BLUEZ
+AC_PATH_GLIB
+AC_PATH_GMODULE
+AC_PATH_DBUS
+AC_PATH_ALSA
+AC_PATH_GSTREAMER
+AC_PATH_USB
+AC_PATH_NETLINK
+AC_PATH_SNDFILE
+
+AC_ARG_BLUEZ
+
+AC_OUTPUT([
+ Makefile
+ doc/Makefile
+ sbc/Makefile
+ eglib/Makefile
+ gdbus/Makefile
+ common/Makefile
+ plugins/Makefile
+ network/Makefile
+ serial/Makefile
+ input/Makefile
+ audio/Makefile
+ tools/Makefile
+ rfcomm/Makefile
+ hcid/Makefile
+ sdpd/Makefile
+ dund/Makefile
+ pand/Makefile
+ hidd/Makefile
+ cups/Makefile
+ test/Makefile
+ scripts/Makefile
+])
diff --git a/utils/cups/Makefile.am b/utils/cups/Makefile.am
new file mode 100644
index 00000000..f01665ee
--- /dev/null
+++ b/utils/cups/Makefile.am
@@ -0,0 +1,17 @@
+
+if CUPS
+cupsdir = $(libdir)/cups/backend
+
+cups_PROGRAMS = bluetooth
+
+bluetooth_SOURCES = main.c cups.h sdp.c spp.c hcrp.c
+
+bluetooth_LDADD = $(top_builddir)/common/libhelper.a \
+ @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/utils/cups/Makefile.in b/utils/cups/Makefile.in
new file mode 100644
index 00000000..5f356dba
--- /dev/null
+++ b/utils/cups/Makefile.in
@@ -0,0 +1,493 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@CUPS_TRUE@cups_PROGRAMS = bluetooth$(EXEEXT)
+subdir = cups
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(cupsdir)"
+cupsPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(cups_PROGRAMS)
+am__bluetooth_SOURCES_DIST = main.c cups.h sdp.c spp.c hcrp.c
+@CUPS_TRUE@am_bluetooth_OBJECTS = main.$(OBJEXT) sdp.$(OBJEXT) \
+@CUPS_TRUE@ spp.$(OBJEXT) hcrp.$(OBJEXT)
+bluetooth_OBJECTS = $(am_bluetooth_OBJECTS)
+@CUPS_TRUE@bluetooth_DEPENDENCIES = \
+@CUPS_TRUE@ $(top_builddir)/common/libhelper.a
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(bluetooth_SOURCES)
+DIST_SOURCES = $(am__bluetooth_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@CUPS_TRUE@cupsdir = $(libdir)/cups/backend
+@CUPS_TRUE@bluetooth_SOURCES = main.c cups.h sdp.c spp.c hcrp.c
+@CUPS_TRUE@bluetooth_LDADD = $(top_builddir)/common/libhelper.a \
+@CUPS_TRUE@ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu cups/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu cups/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-cupsPROGRAMS: $(cups_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(cupsdir)" || $(MKDIR_P) "$(DESTDIR)$(cupsdir)"
+ @list='$(cups_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(cupsPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(cupsdir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(cupsPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(cupsdir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-cupsPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(cups_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(cupsdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(cupsdir)/$$f"; \
+ done
+
+clean-cupsPROGRAMS:
+ @list='$(cups_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+bluetooth$(EXEEXT): $(bluetooth_OBJECTS) $(bluetooth_DEPENDENCIES)
+ @rm -f bluetooth$(EXEEXT)
+ $(LINK) $(bluetooth_OBJECTS) $(bluetooth_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hcrp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spp.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(cupsdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-cupsPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-cupsPROGRAMS
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-cupsPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-cupsPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-cupsPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-cupsPROGRAMS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/cups/cups.h b/utils/cups/cups.h
new file mode 100644
index 00000000..c8de4ab8
--- /dev/null
+++ b/utils/cups/cups.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 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
+ *
+ */
+
+enum { /**** Backend exit codes ****/
+ CUPS_BACKEND_OK = 0, /* Job completed successfully */
+ CUPS_BACKEND_FAILED = 1, /* Job failed, use error-policy */
+ CUPS_BACKEND_AUTH_REQUIRED = 2, /* Job failed, authentication required */
+ CUPS_BACKEND_HOLD = 3, /* Job failed, hold job */
+ CUPS_BACKEND_STOP = 4, /* Job failed, stop queue */
+ CUPS_BACKEND_CANCEL = 5, /* Job failed, cancel job */
+ CUPS_BACKEND_RETRY = 6, /* Failure requires us to retry (BlueZ specific) */
+};
diff --git a/utils/cups/hcrp.c b/utils/cups/hcrp.c
new file mode 100644
index 00000000..5f0211e2
--- /dev/null
+++ b/utils/cups/hcrp.c
@@ -0,0 +1,350 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 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 <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+
+#include <netinet/in.h>
+
+#include "cups.h"
+
+#define HCRP_PDU_CREDIT_GRANT 0x0001
+#define HCRP_PDU_CREDIT_REQUEST 0x0002
+#define HCRP_PDU_GET_LPT_STATUS 0x0005
+
+#define HCRP_STATUS_FEATURE_UNSUPPORTED 0x0000
+#define HCRP_STATUS_SUCCESS 0x0001
+#define HCRP_STATUS_CREDIT_SYNC_ERROR 0x0002
+#define HCRP_STATUS_GENERIC_FAILURE 0xffff
+
+struct hcrp_pdu_hdr {
+ uint16_t pid;
+ uint16_t tid;
+ uint16_t plen;
+} __attribute__ ((packed));
+#define HCRP_PDU_HDR_SIZE 6
+
+struct hcrp_credit_grant_cp {
+ uint32_t credit;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_GRANT_CP_SIZE 4
+
+struct hcrp_credit_grant_rp {
+ uint16_t status;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_GRANT_RP_SIZE 2
+
+struct hcrp_credit_request_rp {
+ uint16_t status;
+ uint32_t credit;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_REQUEST_RP_SIZE 6
+
+struct hcrp_get_lpt_status_rp {
+ uint16_t status;
+ uint8_t lpt_status;
+} __attribute__ ((packed));
+#define HCRP_GET_LPT_STATUS_RP_SIZE 3
+
+static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit)
+{
+ struct hcrp_pdu_hdr hdr;
+ struct hcrp_credit_grant_cp cp;
+ struct hcrp_credit_grant_rp rp;
+ unsigned char buf[128];
+ int len;
+
+ hdr.pid = htons(HCRP_PDU_CREDIT_GRANT);
+ hdr.tid = htons(tid);
+ hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE);
+ cp.credit = credit;
+ memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+ memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE);
+ len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE);
+
+ len = read(sk, buf, sizeof(buf));
+ memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+ memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
+
+ if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
+{
+ struct hcrp_pdu_hdr hdr;
+ struct hcrp_credit_request_rp rp;
+ unsigned char buf[128];
+ int len;
+
+ hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST);
+ hdr.tid = htons(tid);
+ hdr.plen = htons(0);
+ memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+ len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+
+ len = read(sk, buf, sizeof(buf));
+ memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+ memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
+
+ if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+ errno = EIO;
+ return -1;
+ }
+
+ if (credit)
+ *credit = ntohl(rp.credit);
+
+ return 0;
+}
+
+static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
+{
+ struct hcrp_pdu_hdr hdr;
+ struct hcrp_get_lpt_status_rp rp;
+ unsigned char buf[128];
+ int len;
+
+ hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS);
+ hdr.tid = htons(tid);
+ hdr.plen = htons(0);
+ memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+ len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+
+ len = read(sk, buf, sizeof(buf));
+ memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+ memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
+
+ if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+ errno = EIO;
+ return -1;
+ }
+
+ if (lpt_status)
+ *lpt_status = rp.lpt_status;
+
+ return 0;
+}
+
+static inline int hcrp_get_next_tid(int tid)
+{
+ if (tid > 0xf000)
+ return 0;
+ else
+ return tid + 1;
+}
+
+int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class)
+{
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ socklen_t size;
+ unsigned char buf[2048];
+ int i, ctrl_sk, data_sk, mtu, count, len, timeout = 0;
+ uint8_t status;
+ uint16_t tid = 0;
+ uint32_t tmp, credit = 0;
+
+ if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
+ perror("ERROR: Can't create socket");
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+
+ if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't bind socket");
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(ctrl_psm);
+
+ if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't connect to device");
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
+ perror("ERROR: Can't create socket");
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+
+ if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't bind socket");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(data_psm);
+
+ if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't connect to device");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ memset(&opts, 0, sizeof(opts));
+ size = sizeof(opts);
+
+ if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
+ perror("ERROR: Can't get socket options");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ mtu = opts.omtu;
+
+ /* Ignore SIGTERM signals if printing from stdin */
+ if (fd == 0) {
+#ifdef HAVE_SIGSET
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ tid = hcrp_get_next_tid(tid);
+ if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) {
+ fprintf(stderr, "ERROR: Can't grant initial credits\n");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ for (i = 0; i < copies; i++) {
+
+ if (fd != 0) {
+ fprintf(stderr, "PAGE: 1 1\n");
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ while (1) {
+ if (credit < mtu) {
+ tid = hcrp_get_next_tid(tid);
+ if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) {
+ credit += tmp;
+ timeout = 0;
+ }
+ }
+
+ if (!credit) {
+ if (timeout++ > 300) {
+ tid = hcrp_get_next_tid(tid);
+ if (!hcrp_get_lpt_status(ctrl_sk, tid, &status))
+ fprintf(stderr, "ERROR: LPT status 0x%02x\n", status);
+ break;
+ }
+
+ sleep(1);
+ continue;
+ }
+
+ count = read(fd, buf, (credit > mtu) ? mtu : credit);
+ if (count <= 0)
+ break;
+
+ len = write(data_sk, buf, count);
+ if (len < 0) {
+ perror("ERROR: Error writing to device");
+ close(data_sk);
+ close(ctrl_sk);
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (len != count)
+ fprintf(stderr, "ERROR: Can't send complete data\n");
+
+ credit -= len;
+ }
+
+ }
+
+ close(data_sk);
+ close(ctrl_sk);
+
+ return CUPS_BACKEND_OK;
+}
diff --git a/utils/cups/main.c b/utils/cups/main.c
new file mode 100644
index 00000000..001d6788
--- /dev/null
+++ b/utils/cups/main.c
@@ -0,0 +1,711 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "cups.h"
+#include "sdp-xml.h"
+
+extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
+extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
+
+extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class);
+extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class);
+
+#define PRINTER_SERVICE_CLASS_NAME "printer"
+
+struct cups_device {
+ char *bdaddr;
+ char *name;
+ char *id;
+};
+
+static GSList *device_list = NULL;
+static GMainLoop *loop = NULL;
+static DBusConnection *conn = NULL;
+
+#define ATTRID_1284ID 0x0300
+
+static char *parse_xml_sdp(const char *xml)
+{
+ sdp_record_t *sdp_record;
+ sdp_list_t *l;
+ char *str = NULL;
+
+ sdp_record = sdp_xml_parse_record(xml, strlen(xml));
+ if (sdp_record == NULL)
+ return NULL;
+ for (l = sdp_record->attrlist; l != NULL; l = l->next) {
+ sdp_data_t *data;
+
+ data = (sdp_data_t *) l->data;
+ if (data->attrId != ATTRID_1284ID)
+ continue;
+ /* Ignore the length, it's null terminated */
+ str = g_strdup(data->val.str + 2);
+ break;
+ }
+ sdp_record_free(sdp_record);
+
+ return str;
+}
+
+static char *device_get_ieee1284_id(const char *adapter, const char *bdaddr)
+{
+ guint service_handle;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, reply_iter, iter_array;
+ const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb";
+ char *xml, *id;
+
+ /* Look for the service handle of the HCRP service */
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteServiceHandles");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+ dbus_message_unref(reply);
+ return NULL;
+ }
+
+ /* Hopefully we only get one handle, or take a punt */
+ dbus_message_iter_recurse(&reply_iter, &iter_array);
+ while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_UINT32) {
+ dbus_message_iter_get_basic(&iter_array, &service_handle);
+ dbus_message_iter_next(&iter_array);
+ }
+
+ dbus_message_unref(reply);
+
+ /* Now get the XML for the HCRP service record */
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteServiceRecordAsXML");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &service_handle);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ dbus_message_iter_get_basic(&reply_iter, &xml);
+
+ id = parse_xml_sdp(xml);
+
+ dbus_message_unref(reply);
+
+ return id;
+}
+
+static void add_device_to_list(const char *name, const char *bdaddr, const char *id)
+{
+ struct cups_device *device;
+ GSList *l;
+
+ /* Look for the device in the list */
+ for (l = device_list; l != NULL; l = l->next) {
+ device = (struct cups_device *) l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ g_free(device->name);
+ device->name = g_strdup(name);
+ return;
+ }
+ }
+
+ /* Or add it to the list if it's not there */
+ device = g_new0(struct cups_device, 1);
+ device->bdaddr = g_strdup(bdaddr);
+ device->name = g_strdup(name);
+ device->id = g_strdup(id);
+
+ device_list = g_slist_prepend(device_list, device);
+}
+
+static char *escape_name(const char *str, char orig, char dest)
+{
+ char *ret, *s;
+
+ ret = g_strdup(str);
+ while ((s = strchr(ret, orig)) != NULL)
+ s[0] = dest;
+ return ret;
+}
+
+static void print_printer_details(const char *name, const char *bdaddr, const char *id)
+{
+ char *uri, *escaped;
+ guint len;
+
+ escaped = escape_name(name, '\"', '\'');
+ len = strlen("bluetooth://") + 12 + 1;
+ uri = g_malloc(len);
+ snprintf(uri, len, "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);
+}
+
+static gboolean device_is_printer(const char *adapter, const char *bdaddr)
+{
+ char *class;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, reply_iter;
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteMinorClass");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return FALSE;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ dbus_message_iter_get_basic(&reply_iter, &class);
+
+ if (class != NULL && strcmp(class, PRINTER_SERVICE_CLASS_NAME) == 0) {
+ dbus_message_unref(reply);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char *device_get_name(const char *adapter, const char *bdaddr)
+{
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, reply_iter;
+ char *name;
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteName");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ dbus_message_iter_get_basic(&reply_iter, &name);
+
+ name = g_strdup(name);
+ dbus_message_unref(reply);
+
+ return name;
+}
+
+static void remote_device_found(const char *adapter, const char *bdaddr, guint class, int rssi)
+{
+ uint8_t major_index = (class >> 8) & 0x1F;
+ uint8_t minor_index;
+ uint8_t shift_minor = 0;
+ gboolean found = FALSE;
+ char *name, *id;
+
+ /* Check if we have a printer
+ * From hcid/dbus-adapter.c minor_class_str() */
+ if (major_index != 6)
+ return;
+
+ minor_index = (class >> 4) & 0x0F;
+ while (shift_minor < 4) {
+ if (((minor_index >> shift_minor) & 0x01) == 0x01) {
+ if (shift_minor == 3) {
+ found = TRUE;
+ break;
+ }
+ }
+ shift_minor++;
+ }
+
+ if (!found)
+ return;
+
+ name = device_get_name(adapter, bdaddr);
+ id = device_get_ieee1284_id(adapter, bdaddr);
+ add_device_to_list(name, bdaddr, id);
+ g_free(name);
+ g_free(id);
+}
+
+static void remote_name_updated(const char *bdaddr, const char *name)
+{
+ add_device_to_list(name, bdaddr, NULL);
+}
+
+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 = escape_name(device->bdaddr, ':', '-');
+ 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;
+
+ g_main_loop_quit(loop);
+}
+
+static void remote_device_disappeared(const char *bdaddr)
+{
+ GSList *l;
+
+ for (l = device_list; l != NULL; l = l->next) {
+ struct cups_device *device = (struct cups_device *) l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ g_free(device->name);
+ g_free(device->bdaddr);
+ g_free(device);
+ device_list = g_slist_delete_link(device_list, l);
+ return;
+ }
+ }
+}
+
+static gboolean list_known_printers(const char *adapter)
+{
+ DBusMessageIter reply_iter, iter_array;
+ DBusError error;
+ DBusMessage *message, *reply;
+
+ message = dbus_message_new_method_call ("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "ListRemoteDevices");
+ if (message == NULL)
+ return FALSE;
+
+ dbus_error_init(&error);
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, &error);
+
+ dbus_message_unref(message);
+
+ if (&error != NULL && dbus_error_is_set(&error))
+ return FALSE;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+ dbus_message_unref(reply);
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse(&reply_iter, &iter_array);
+ while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_STRING) {
+ char *bdaddr;
+
+ dbus_message_iter_get_basic(&iter_array, &bdaddr);
+ if (device_is_printer(adapter, bdaddr)) {
+ char *name, *id;
+ name = device_get_name(adapter, bdaddr);
+ id = device_get_ieee1284_id(adapter, bdaddr);
+ add_device_to_list(name, bdaddr, id);
+ g_free(name);
+ g_free(id);
+ }
+ dbus_message_iter_next(&iter_array);
+ }
+
+ dbus_message_unref(reply);
+
+ return FALSE;
+}
+
+static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+ const char *adapter;
+
+ if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "RemoteDeviceFound")) {
+ char *bdaddr;
+ guint class;
+ int rssi;
+
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &bdaddr,
+ DBUS_TYPE_UINT32, &class,
+ DBUS_TYPE_INT32, &rssi,
+ DBUS_TYPE_INVALID);
+ adapter = dbus_message_get_path(message);
+ remote_device_found(adapter, bdaddr, class, rssi);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "RemoteNameUpdated")) {
+ char *bdaddr, *name;
+
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &bdaddr,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+ remote_name_updated(bdaddr, name);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "RemoteDeviceDisappeared")) {
+ char *bdaddr;
+
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &bdaddr,
+ DBUS_TYPE_INVALID);
+ remote_device_disappeared(bdaddr);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "DiscoveryCompleted")) {
+ discovery_completed();
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean list_printers(void)
+{
+ /* 1. Connect to the bus
+ * 2. Get the manager
+ * 3. Get the default adapter
+ * 4. Get a list of devices
+ * 5. Get the class of each device
+ * 6. Print the details from each printer device
+ */
+ DBusError error;
+ dbus_bool_t hcid_exists;
+ DBusMessage *reply, *message;
+ DBusMessageIter reply_iter;
+ char *adapter, *match;
+ guint len;
+
+ conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+ if (conn == NULL)
+ return FALSE;
+
+ dbus_error_init(&error);
+ hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
+ if (&error != NULL && dbus_error_is_set(&error))
+ return FALSE;
+
+ if (!hcid_exists)
+ return FALSE;
+
+ /* Get the default adapter */
+ message = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.Manager",
+ "DefaultAdapter");
+ if (message == NULL) {
+ dbus_connection_unref(conn);
+ return FALSE;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, &error);
+
+ dbus_message_unref(message);
+
+ if (&error != NULL && dbus_error_is_set(&error)) {
+ dbus_connection_unref(conn);
+ return FALSE;
+ }
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) {
+ dbus_message_unref(reply);
+ dbus_connection_unref(conn);
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(&reply_iter, &adapter);
+ adapter = g_strdup(adapter);
+ dbus_message_unref(reply);
+
+ if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) {
+ g_free(adapter);
+ dbus_connection_unref(conn);
+ return FALSE;
+ }
+
+#define MATCH_FORMAT \
+ "type='signal'," \
+ "interface='org.bluez.Adapter'," \
+ "sender='org.bluez'," \
+ "path='%s'"
+
+ len = strlen(MATCH_FORMAT) - 2 + strlen(adapter) + 1;
+ match = g_malloc(len);
+ snprintf(match, len, "type='signal',"
+ "interface='org.bluez.Adapter',"
+ "sender='org.bluez',"
+ "path='%s'",
+ adapter);
+ dbus_bus_add_match(conn, match, &error);
+ g_free(match);
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "DiscoverDevicesWithoutNameResolving");
+
+ if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
+ dbus_message_unref(message);
+ dbus_connection_unref(conn);
+ g_free(adapter);
+ return FALSE;
+ }
+ dbus_message_unref(message);
+
+ /* Also add the the recent devices */
+ g_timeout_add(0, (GSourceFunc) list_known_printers, adapter);
+
+ loop = g_main_loop_new(NULL, TRUE);
+ g_main_loop_run(loop);
+
+ dbus_connection_unref(conn);
+
+ return TRUE;
+}
+
+/*
+ * Usage: printer-uri job-id user title copies options [file]
+ *
+ */
+
+int main(int argc, char *argv[])
+{
+ sdp_session_t *sdp;
+ bdaddr_t bdaddr;
+ unsigned short ctrl_psm, data_psm;
+ uint8_t channel, b[6];
+ char *ptr, str[3], device[18], service[12];
+ const char *uri, *cups_class;
+ int i, err, fd, copies, proto;
+
+ /* Make sure status messages are not buffered */
+ setbuf(stderr, NULL);
+
+ /* Ignore SIGPIPE signals */
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ if (argc == 1) {
+ if (list_printers() == TRUE)
+ return CUPS_BACKEND_OK;
+ else
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (argc < 6 || argc > 7) {
+ fprintf(stderr, "Usage: bluetooth job-id user title copies options [file]\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (argc == 6) {
+ fd = 0;
+ copies = 1;
+ } else {
+ if ((fd = open(argv[6], O_RDONLY)) < 0) {
+ perror("ERROR: Unable to open print file");
+ return CUPS_BACKEND_FAILED;
+ }
+ copies = atoi(argv[4]);
+ }
+
+ uri = getenv("DEVICE_URI");
+ if (!uri)
+ uri = argv[0];
+
+ if (strncasecmp(uri, "bluetooth://", 12)) {
+ fprintf(stderr, "ERROR: No device URI found\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ ptr = argv[0] + 12;
+ for (i = 0; i < 6; i++) {
+ strncpy(str, ptr, 2);
+ b[i] = (uint8_t) strtol(str, NULL, 16);
+ ptr += 2;
+ }
+ sprintf(device, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ b[0], b[1], b[2], b[3], b[4], b[5]);
+
+ str2ba(device, &bdaddr);
+
+ ptr = strchr(ptr, '/');
+ if (ptr) {
+ strncpy(service, ptr + 1, 12);
+
+ if (!strncasecmp(ptr + 1, "spp", 3))
+ proto = 1;
+ else if (!strncasecmp(ptr + 1, "hcrp", 4))
+ proto = 2;
+ else
+ proto = 0;
+ } else {
+ strcpy(service, "auto");
+ proto = 0;
+ }
+
+ cups_class = getenv("CLASS");
+
+ fprintf(stderr, "DEBUG: %s device %s service %s fd %d copies %d class %s\n",
+ argv[0], device, service, fd, copies,
+ cups_class ? cups_class : "(none)");
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+
+service_search:
+ sdp = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
+ if (!sdp) {
+ fprintf(stderr, "ERROR: Can't open Bluetooth connection\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ switch (proto) {
+ case 1:
+ err = sdp_search_spp(sdp, &channel);
+ break;
+ case 2:
+ err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
+ break;
+ default:
+ proto = 2;
+ err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
+ if (err) {
+ proto = 1;
+ err = sdp_search_spp(sdp, &channel);
+ }
+ break;
+ }
+
+ sdp_close(sdp);
+
+ if (err) {
+ if (cups_class) {
+ fputs("INFO: Unable to contact printer, queuing on "
+ "next printer in class...\n", stderr);
+ sleep(5);
+ return CUPS_BACKEND_FAILED;
+ }
+ sleep(20);
+ fprintf(stderr, "ERROR: Can't get service information\n");
+ goto service_search;
+ }
+
+connect:
+ switch (proto) {
+ case 1:
+ err = spp_print(BDADDR_ANY, &bdaddr, channel,
+ fd, copies, cups_class);
+ break;
+ case 2:
+ err = hcrp_print(BDADDR_ANY, &bdaddr, ctrl_psm, data_psm,
+ fd, copies, cups_class);
+ break;
+ default:
+ err = CUPS_BACKEND_FAILED;
+ fprintf(stderr, "ERROR: Unsupported protocol\n");
+ break;
+ }
+
+ if (err == CUPS_BACKEND_FAILED && cups_class) {
+ fputs("INFO: Unable to contact printer, queuing on "
+ "next printer in class...\n", stderr);
+ sleep(5);
+ return CUPS_BACKEND_FAILED;
+ } else if (err == CUPS_BACKEND_RETRY) {
+ sleep(20);
+ goto connect;
+ }
+
+ if (fd != 0)
+ close(fd);
+
+ if (!err)
+ fprintf(stderr, "INFO: Ready to print\n");
+
+ return err;
+}
diff --git a/utils/cups/sdp.c b/utils/cups/sdp.c
new file mode 100644
index 00000000..62f5c491
--- /dev/null
+++ b/utils/cups/sdp.c
@@ -0,0 +1,117 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 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 <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm)
+{
+ sdp_list_t *srch, *attrs, *rsp;
+ uuid_t svclass;
+ uint16_t attr1, attr2;
+ int err;
+
+ if (!sdp)
+ return -1;
+
+ sdp_uuid16_create(&svclass, HCR_PRINT_SVCLASS_ID);
+ srch = sdp_list_append(NULL, &svclass);
+
+ attr1 = SDP_ATTR_PROTO_DESC_LIST;
+ attrs = sdp_list_append(NULL, &attr1);
+ attr2 = SDP_ATTR_ADD_PROTO_DESC_LIST;
+ attrs = sdp_list_append(attrs, &attr2);
+
+ err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+ if (err)
+ return -1;
+
+ for (; rsp; rsp = rsp->next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
+ sdp_list_t *protos;
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
+ if (psm > 0) {
+ *ctrl_psm = psm;
+ }
+ }
+
+ if (!sdp_get_add_access_protos(rec, &protos)) {
+ unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
+ if (psm > 0 && *ctrl_psm > 0) {
+ *data_psm = psm;
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel)
+{
+ sdp_list_t *srch, *attrs, *rsp;
+ uuid_t svclass;
+ uint16_t attr;
+ int err;
+
+ if (!sdp)
+ return -1;
+
+ sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
+ srch = sdp_list_append(NULL, &svclass);
+
+ attr = SDP_ATTR_PROTO_DESC_LIST;
+ attrs = sdp_list_append(NULL, &attr);
+
+ err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+ if (err)
+ return -1;
+
+ for (; rsp; rsp = rsp->next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
+ sdp_list_t *protos;
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ if (ch > 0) {
+ *channel = ch;
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
diff --git a/utils/cups/spp.c b/utils/cups/spp.c
new file mode 100644
index 00000000..cd9bfd58
--- /dev/null
+++ b/utils/cups/spp.c
@@ -0,0 +1,116 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 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 <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "cups.h"
+
+int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class)
+{
+ struct sockaddr_rc addr;
+ unsigned char buf[2048];
+ int i, sk, err, len;
+
+ if ((sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
+ perror("ERROR: Can't create socket");
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = 0;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't bind socket");
+ close(sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, dst);
+ addr.rc_channel = channel;
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't connect to device");
+ close(sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ /* Ignore SIGTERM signals if printing from stdin */
+ if (fd == 0) {
+#ifdef HAVE_SIGSET
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ for (i = 0; i < copies; i++) {
+
+ if (fd != 0) {
+ fprintf(stderr, "PAGE: 1 1\n");
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ while ((len = read(fd, buf, sizeof(buf))) > 0) {
+ err = write(sk, buf, len);
+ if (err < 0) {
+ perror("ERROR: Error writing to device");
+ close(sk);
+ return CUPS_BACKEND_FAILED;
+ }
+ }
+
+ }
+
+ close(sk);
+
+ return CUPS_BACKEND_OK;
+}
diff --git a/utils/depcomp b/utils/depcomp
new file mode 100755
index 00000000..e5f9736c
--- /dev/null
+++ b/utils/depcomp
@@ -0,0 +1,589 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2007-03-29.01
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007 Free Software
+# Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
+ sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/utils/doc/Makefile.am b/utils/doc/Makefile.am
new file mode 100644
index 00000000..5505391e
--- /dev/null
+++ b/utils/doc/Makefile.am
@@ -0,0 +1,5 @@
+
+EXTRA_DIST = manager-api.txt adapter-api.txt device-api.txt agent-api.txt \
+ serial-api.txt network-api.txt input-api.txt audio-api.txt
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/doc/Makefile.in b/utils/doc/Makefile.in
new file mode 100644
index 00000000..37c0ec8a
--- /dev/null
+++ b/utils/doc/Makefile.in
@@ -0,0 +1,348 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = manager-api.txt adapter-api.txt device-api.txt agent-api.txt \
+ serial-api.txt network-api.txt input-api.txt audio-api.txt
+
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu doc/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/doc/adapter-api.txt b/utils/doc/adapter-api.txt
new file mode 100644
index 00000000..a05bf620
--- /dev/null
+++ b/utils/doc/adapter-api.txt
@@ -0,0 +1,284 @@
+BlueZ D-Bus Adapter API description
+***********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2005-2006 Johan Hedberg <johan.hedberg@nokia.com>
+Copyright (C) 2005-2006 Claudio Takahasi <claudio.takahasi@indt.org.br>
+Copyright (C) 2006-2007 Luiz von Dentz <luiz.dentz@indt.org.br>
+
+
+Adapter hierarchy
+=================
+
+Service org.bluez
+Interface org.bluez.Adapter
+Object path /{hci0,hci1,...}
+
+Methods dict GetProperties()
+
+ Returns all properties for the adapter. See the
+ properties section for available properties.
+
+ Possible Errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.InvalidArguments
+
+ void SetProperty(string name, variant value)
+
+ Changes the value of the specified property. Only
+ properties that are listed a read-write are changeable.
+ On success this will emit a PropertyChanged signal.
+
+ Possible Errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.InvalidArguments
+
+ void RequestMode(string mode)
+
+ This method will request a mode change. The mode
+ change must be confirmed by the user via the agent.
+
+ Possible modes for this call are "connectable" and
+ "discoverable". Any application that wants to use
+ Bluetooth functionality can use this method to
+ indicate which mode it needs to operate sucessfully.
+
+ In case the user doesn't confirm the mode change it
+ will return an error to indicate this rejection.
+
+ Possible Errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.InvalidArguments
+ org.bluez.Error.Rejected
+
+ void ReleaseMode()
+
+ Releases a mode requested via RequestMode.
+
+ Possible Errors: org.bluez.Error.DoesNotExist
+
+ void DiscoverDevices()
+
+ This method starts the device discovery procedure. This
+ includes an inquiry procedure and remote device name
+ resolving.
+
+ On start up this process will generate a DiscoveryStarted
+ signal and then return DeviceFound singals. If the
+ procedure has been finished an DiscoveryCompleted
+ signal will be sent.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InProgress
+ org.bluez.Error.NoSuchAdapter
+
+ void CancelDiscovery()
+
+ This method will cancel any previous DiscoverDevices
+ transaction.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.NotAuthorized
+ org.bluez.Error.NoSuchAdapter
+
+ object FindDevice(string address)
+
+ Returns the object path of device for given address.
+ The device object needs to be first created via
+ CreateDevice or CreatePairedDevice.
+
+ Possible Errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.InvalidArguments
+
+ array{object} ListDevices()
+
+ Returns list of device object paths.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+ org.bluez.Error.OutOfMemory
+
+ object CreateDevice(string address)
+
+ Creates a new object path for a remote device. This
+ method will connect to the remote device and retrieve
+ all SDP records.
+
+ If the object for the remote device already exists
+ this method will fail.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ object CreatePairedDevice(string address, object agent,
+ string capability)
+
+ Creates a new object path for a remote device. This
+ method will connect to the remote device and retrieve
+ all SDP records and then initiate the pairing.
+
+ If previously CreateDevice was used successfully,
+ this method will only initiate the pairing.
+
+ Compared to CreateDevice this method will fail if
+ the pairing already exists, but not if the object
+ path already has been created. This allows applications
+ to use CreateDevice first and the if needed use
+ CreatePairedDevice to initiate pairing.
+
+ The capability parameter is the same as for the
+ RegisterAgent method.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void RemoveDevice(object device)
+
+ This removes the remote device object at the given
+ path. It will remove also the pairing information.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void RegisterAgent(object agent, string capability)
+
+ This registers the adapter wide agent.
+
+ The object path defines the path the of the agent
+ that will be called when user input is needed.
+
+ If an application disconnects from the bus all
+ of its registered agents will be removed.
+
+ The capability parameter can have the values
+ "DisplayOnly", "DisplayYesNo", "KeyboardOnly" and
+ "NoInputNoOutput" which reflects the input and output
+ capabilities of the agent. If an empty string is
+ used it will fallback to "DisplayYesNo".
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+
+ void UnregisterAgent(object agent)
+
+ This unregisters the agent that has been previously
+ registered. The object path parameter must match the
+ same value that has been used on registration.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+ uint32 AddServiceRecord(string record)
+
+ Adds a new service record from the XML description
+ and returns the assigned record handle.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void UpdateServiceRecord(uint32 handle, string record)
+
+ Updates a given service record provided in the
+ XML format.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+ org.bluez.Error.Failed
+
+ void RemoveServiceRecord(uint32 handle)
+
+ Remove a service record identified by its handle.
+
+ It is only possible to remove service records that
+ where added by the current connection.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAuthorized
+ org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+ void RequestAuthorization(string address, uint32 handle)
+
+ Request an authorization for an incoming connection
+ for a specific service record. The service record
+ needs to be registered via AddServiceRecord first.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAuthorized
+ org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+ void CancelAuthorization()
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAuthorized
+ org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+ DiscoveryStarted()
+
+ This signal indicates that a device discovery
+ procedure has been started.
+
+ DiscoveryCompleted()
+
+ This signal indicates that a device discovery
+ procedure has been completed.
+
+ DeviceFound(string address, dict values)
+
+ This signal will be send every time an inquiry result
+ has been found by the service daemon. In general they
+ only appear during a device discovery.
+
+ The dictionary can contain bascially the same values
+ that we be returned by the GetProperties method
+ from the org.bluez.Device interface. In addition there
+ can be values for the RSSI and the TX power level.
+
+ DeviceDisappeared(string address)
+
+ This signal will be send when an inquiry session for
+ a periodic discovery finishes and previously found
+ devices are no longer in range or visible.
+
+ DeviceCreated(object device)
+
+ Parameter is object path of created device.
+
+ DeviceRemoved(object device)
+
+ Parameter is object path of removed device.
+
+Properties string Address [readonly]
+
+ The Bluetooth device address.
+
+ string Name [readwrite]
+
+ The Bluetooth friendly name. This value can be
+ changed and a PropertyChanged signal will be emitted.
+
+ string Mode [readwrite]
+
+ The Bluetooth operation mode.
+
+ Valid modes: "off", "connectable",
+ "discoverable", "limited"
+
+ uint32 DiscoverableTimeout [readwrite]
+
+ The discoverable timeout in seconds. A value of zero
+ means that the timeout is disabled and it will stay in
+ discoverable/limited mode forever.
+
+ The default value for the discoverable timeout should
+ be 180 seconds (3 minutes).
+
+ boolean PeriodicDiscovery [readwrite]
+
+ Is peridoic inquiry active or not. Changing this
+ property will either enable or disable it.
diff --git a/utils/doc/agent-api.txt b/utils/doc/agent-api.txt
new file mode 100644
index 00000000..7e3fa3a9
--- /dev/null
+++ b/utils/doc/agent-api.txt
@@ -0,0 +1,91 @@
+BlueZ D-Bus Agent API description
+**********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2005-2006 Johan Hedberg <johan.hedberg@nokia.com>
+
+
+Agent hierarchy
+===============
+
+Service unique name
+Interface org.bluez.Agent
+Object path freely definable
+
+Methods void Release()
+
+ This method gets called when the service daemon
+ unregisters the agent. An agent can use it to do
+ cleanup tasks. There is no need to unregister the
+ agent, because when this method gets called it has
+ already been unregistered.
+
+ string RequestPinCode(object device)
+
+ This method gets called when the service daemon
+ needs to get the passkey for an authentication.
+
+ The return value should be a string of 1-16 characters
+ length. The string can be alphanumeric.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ uint32 RequestPasskey(object device)
+
+ This method gets called when the service daemon
+ needs to get the passkey for an authentication.
+
+ The return value should be a numeric value
+ between 0-999999.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void DisplayPasskey(object device, uint32 passkey, uint8 entered)
+
+ This method gets called when the service daemon
+ needs to display a passkey for an authentication.
+
+ The entered parameter indicates the number of already
+ typed keys on the remote side.
+
+ An empty reply should be returned. When the passkey
+ needs no longer to be displayed, the Cancel method
+ of the agent will be called.
+
+ During the pairing process this method might be
+ called multiple times to update the entered value.
+
+ void RequestConfirmation(object device, uint32 passkey)
+
+ This method gets called when the service daemon
+ needs to confirm a passkey for an authentication.
+
+ To confirm the value it should return an empty reply
+ or an error in case the passkey is invalid.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void Authorize(object device, string uuid)
+
+ This method gets called when the service daemon
+ needs to authorize a connection/service request.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void ConfirmModeChange(string mode)
+
+ This method gets called if a mode change is requested
+ that needs to be confirmed by the user. An example
+ would be leaving flight mode.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void Cancel()
+
+ This method gets called to indicate that the agent
+ request failed before a reply was returned.
diff --git a/utils/doc/audio-api.txt b/utils/doc/audio-api.txt
new file mode 100644
index 00000000..b9f0a920
--- /dev/null
+++ b/utils/doc/audio-api.txt
@@ -0,0 +1,136 @@
+BlueZ D-Bus Audio API description
+*********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com>
+Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+
+
+Headset hierarchy
+=================
+
+Service org.bluez
+Interface org.bluez.Headset
+Object path /{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods void Connect()
+
+ Connect to the HSP/HFP service on the remote device.
+
+ void Disconnect()
+
+ Disconnect from the HSP/HFP service on the remote
+ device.
+
+ boolean IsConnected()
+
+ Returns TRUE if there is a active connection to the
+ HSP/HFP connection on the remote device.
+
+ void IndicateCall()
+
+ Indicate an incoming call on the headset
+ connected to the stream. Will continue to
+ ring the headset about every 3 seconds.
+
+ void CancelCall()
+
+ Cancel the incoming call indication.
+
+ void Play()
+
+ Open the audio connection to the headset.
+
+ void Stop()
+
+ Close the audio connection.
+
+ boolean IsPlaying()
+
+ Returns true if an audio connection to the headset
+ is active.
+
+ uint16 GetSpeakerGain()
+
+ Returns the current speaker gain if available,
+ otherwise returns the error NotAvailable.
+
+ uint16 GetMicrophoneGain()
+
+ Returns the current microphone gain if available,
+ otherwise returns the error NotAvailable.
+
+ void SetSpeakerGain(uint16 gain)
+
+ Changes the current speaker gain if possible.
+
+ void SetMicrophoneGain(uint16 gain)
+
+ Changes the current speaker gain if possible.
+
+Signals void AnswerRequested()
+
+ Sent when the answer button is pressed on the headset
+
+ void Connected()
+
+ Sent when the device has been connected to.
+
+ void Disconnected()
+
+ Sent when the device has been disconnected from.
+
+ void Stopped()
+
+ Sent when the audio connection is closed
+
+ void Playing()
+
+ Sent when the audio connection is opened
+
+ void SpeakerGainChanged(uint16 gain)
+
+ The speaker gain changed.
+
+ void MicrophoneGainChanged(uint16 gain)
+
+ The microphone gain changed.
+
+
+Sink hierarchy
+==============
+
+Service org.bluez
+Interface org.bluez.Sink
+Object path /{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods void Connect()
+
+ Connect and setup a stream to a A2DP sink on the
+ remote device.
+
+ void Disconnect()
+
+ Disconnect from the remote device.
+
+ boolean IsConnected()
+
+ Returns TRUE if a stream is setup to a A2DP sink on
+ the remote device.
+
+Signals void Connected()
+
+ Sent when a successful connection has been made to the
+ remote A2DP Sink
+
+ void Disconnected()
+
+ Sent when the device has been disconnected from.
+
+ void Playing()
+
+ Sent when a stream with remote device is started.
+
+ void Stopped()
+
+ Sent when a stream with remote device is suspended.
diff --git a/utils/doc/device-api.txt b/utils/doc/device-api.txt
new file mode 100644
index 00000000..059398df
--- /dev/null
+++ b/utils/doc/device-api.txt
@@ -0,0 +1,133 @@
+BlueZ D-Bus Device API description
+**********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2005-2006 Johan Hedberg <johan.hedberg@nokia.com>
+Copyright (C) 2005-2006 Claudio Takahasi <claudio.takahasi@indt.org.br>
+Copyright (C) 2006-2007 Luiz von Dentz <luiz.dentz@indt.org.br>
+
+
+Device hierarchy
+================
+
+Service org.bluez
+Interface org.bluez.Device
+Object path /{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods dict GetProperties()
+
+ Returns all properties for the adapter. See the
+ properties section for available properties.
+
+ Possible Errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.InvalidArguments
+
+ void SetProperty(string name, variant value)
+
+ Changes the value of the specified property. Only
+ properties that are listed a read-write are changeable.
+ On success this will emit a PropertyChanged signal.
+
+ Possible Errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.InvalidArguments
+
+ dict DiscoverServices(string pattern)
+
+ This method starts the service discovery to retrieve
+ remote service records. The pattern parameter can
+ be used to specific specific UUIDs.
+
+ The return value is a dictionary with the record
+ handles as keys and the service record in XML format
+ as values. The key is uint32 and the value a string
+ for this dictionary.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InProgress
+
+ void CancelDiscovery()
+
+ This method will cancel any previous DiscoverServices
+ transaction.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.NotAuthorized
+
+ void Disconnect()
+
+ This method disconnects a specific remote device by
+ terminating the low-level ACL connection. The use of
+ this method should be restricted to administrator
+ use.
+
+ A DisconnectRequested signal will be sent and the
+ actual disconnection will only happen 2 seconds later.
+ This enables upper-level applications to terminate
+ their connections gracefully before the ACL connection
+ is terminated.
+
+ Possible errors: org.bluez.Error.NotConnected
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+ DisconnectRequested()
+
+ This signal will be sent when a low level
+ disconnection to a remote device has been requested.
+ The actual disconnection will happen 2 seconds later.
+
+Properties string Address [readonly]
+
+ The Bluetooth device address of the remote device.
+
+ string Name [readonly]
+
+ The Bluetooth remote name. This value can not be
+ changed. Use the Alias property instead.
+
+ uint32 Class [readonly]
+
+ The Bluetooth class of device of the remote device.
+
+ array{string} UUIDs [readonly]
+
+ List of 128-bit UUIDs that represents the available
+ remote services.
+
+ boolean Paired [readonly]
+
+ Indicates if the remote device is paired.
+
+ boolean Connected [readonly]
+
+ Indicates if the remote device is currently connected.
+ A PropertyChanged signal indicate changes to this
+ status.
+
+ boolean Trusted [readwrite]
+
+ Indicates if the remote is seen as trusted. This
+ setting can be changed by the application.
+
+ string Alias [readwrite]
+
+ The name alias for the remote device. The alias can
+ be used to have a different friendly name for the
+ remote device.
+
+ In case no alias is set, it will return the remote
+ device name. Setting an empty string as alias will
+ convert it back to the remote device name.
+
+ When reseting the alias with an empty string, the
+ emitted PropertyChanged signal will show the remote
+ name again.
+
+ object Adapter [readonly]
+
+ The object path of the adpater the device belongs to.
diff --git a/utils/doc/input-api.txt b/utils/doc/input-api.txt
new file mode 100644
index 00000000..c0816eec
--- /dev/null
+++ b/utils/doc/input-api.txt
@@ -0,0 +1,36 @@
+BlueZ D-Bus Input API description
+*********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+
+
+Input hierarchy
+===============
+
+Service org.bluez
+Interface org.bluez.Input
+Object path /{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods void Connect()
+
+ Connect to the input device.
+
+ Possible errors: org.bluez.Error.AlreadyConnected
+ org.bluez.Error.ConnectionAttemptFailed
+
+ void Disconnect()
+
+ Disconnect from the input device.
+
+ To abort a connection attempt in case of errors or
+ timeouts in the client it is fine to call this method.
+
+ Possible errors: org.bluez.Error.Failed
+
+ bool IsConnected()
+
+ Returns the connection status.
+
+Signals void Connected()
+
+ void Disconnected()
diff --git a/utils/doc/manager-api.txt b/utils/doc/manager-api.txt
new file mode 100644
index 00000000..ba45504a
--- /dev/null
+++ b/utils/doc/manager-api.txt
@@ -0,0 +1,56 @@
+BlueZ D-Bus Manager API description
+***********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2005-2006 Johan Hedberg <johan.hedberg@nokia.com>
+Copyright (C) 2005-2006 Claudio Takahasi <claudio.takahasi@indt.org.br>
+Copyright (C) 2006-2007 Luiz von Dentz <luiz.dentz@indt.org.br>
+
+
+Manager hierarchy
+=================
+
+Service org.bluez
+Interface org.bluez.Manager
+Object path /
+
+Methods object DefaultAdapter()
+
+ Returns object path for the default adapter.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NoSuchAdapter
+
+ object FindAdapter(string pattern)
+
+ Returns object path for the specified adapter. Valid
+ patterns are "hci0" or "00:11:22:33:44:55".
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NoSuchAdapter
+
+ array{object} ListAdapters()
+
+ Returns list of adapter object paths under /org/bluez
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+ org.bluez.Error.OutOfMemory
+
+Signals AdapterAdded(object adapter)
+
+ Parameter is object path of added adapter.
+
+ AdapterRemoved(object adapter)
+
+ Parameter is object path of removed adapter.
+
+ DefaultAdapterChanged(object adapter)
+
+ Parameter is object path of the new default adapter,
+ or an empty string if there is no available adapters.
+
+ In case all adapters are removed this signal will not
+ be emitted. The AdapterRemoved signal has to be used
+ to detect that no default adapter is selected or
+ available anymore.
diff --git a/utils/doc/network-api.txt b/utils/doc/network-api.txt
new file mode 100644
index 00000000..a59c8972
--- /dev/null
+++ b/utils/doc/network-api.txt
@@ -0,0 +1,38 @@
+BlueZ D-Bus Network API description
+***********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+
+
+Network hierarchy
+=================
+
+Service org.bluez
+Interface org.bluez.Network
+Object path /{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+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.
+
+ Possible errors: org.bluez.Error.AlreadyConnected
+ org.bluez.Error.ConnectionAttemptFailed
+
+ void Disconnect()
+
+ Disconnect from the network device.
+
+ To abort a connection attempt in case of errors or
+ timeouts in the client it is fine to call this method.
+
+ Possible errors: org.bluez.Error.Failed
+
+ bool IsConnected()
+
+ Returns the connection status.
+
+Signals void Connected(string device, string uuid)
+
+ void Disconnected(string device)
diff --git a/utils/doc/serial-api.txt b/utils/doc/serial-api.txt
new file mode 100644
index 00000000..21c4f220
--- /dev/null
+++ b/utils/doc/serial-api.txt
@@ -0,0 +1,37 @@
+BlueZ D-Bus Serial API description
+**********************************
+
+Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+
+
+Serial hierarchy
+================
+
+Service org.bluez
+Interface org.bluez.Serial
+Object path /{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods string Connect(string uuid)
+
+ Connects to a specific RFCOMM based service on a
+ remote device and then creates a RFCOMM TTY
+ device for it. The RFCOMM TTY device is returned.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.InProgress
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.NotSupported
+
+ void Disconnect(string device)
+
+ Disconnect a RFCOMM TTY device that has been
+ created by Connect method.
+
+ To abort a connection attempt in case of errors or
+ timeouts in the client it is fine to call this method.
+
+ In that case the UUID of the Connect method should
+ be suplied instead of the TTY device.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.DoesNotExist
diff --git a/utils/dund/Makefile.am b/utils/dund/Makefile.am
new file mode 100644
index 00000000..260698ab
--- /dev/null
+++ b/utils/dund/Makefile.am
@@ -0,0 +1,20 @@
+
+if DUND
+bin_PROGRAMS = dund
+
+dund_SOURCES = main.c dun.c dund.h sdp.c lib.h msdun.c
+
+dund_LDADD = @BLUEZ_LIBS@
+endif
+
+AM_CFLAGS = @BLUEZ_CFLAGS@
+
+if DUND
+if MANPAGES
+man_MANS = dund.1
+endif
+endif
+
+EXTRA_DIST = dund.1
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/dund/Makefile.in b/utils/dund/Makefile.in
new file mode 100644
index 00000000..a7b3fe48
--- /dev/null
+++ b/utils/dund/Makefile.in
@@ -0,0 +1,540 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@DUND_TRUE@bin_PROGRAMS = dund$(EXEEXT)
+subdir = dund
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__dund_SOURCES_DIST = main.c dun.c dund.h sdp.c lib.h msdun.c
+@DUND_TRUE@am_dund_OBJECTS = main.$(OBJEXT) dun.$(OBJEXT) \
+@DUND_TRUE@ sdp.$(OBJEXT) msdun.$(OBJEXT)
+dund_OBJECTS = $(am_dund_OBJECTS)
+dund_DEPENDENCIES =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(dund_SOURCES)
+DIST_SOURCES = $(am__dund_SOURCES_DIST)
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@DUND_TRUE@dund_SOURCES = main.c dun.c dund.h sdp.c lib.h msdun.c
+@DUND_TRUE@dund_LDADD = @BLUEZ_LIBS@
+AM_CFLAGS = @BLUEZ_CFLAGS@
+@DUND_TRUE@@MANPAGES_TRUE@man_MANS = dund.1
+EXTRA_DIST = dund.1
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu dund/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu dund/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+dund$(EXEEXT): $(dund_OBJECTS) $(dund_DEPENDENCIES)
+ @rm -f dund$(EXEEXT)
+ $(LINK) $(dund_OBJECTS) $(dund_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msdun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdp.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(man1_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-man \
+ uninstall-man1
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/dund/dun.c b/utils/dund/dun.c
new file mode 100644
index 00000000..de437cf4
--- /dev/null
+++ b/utils/dund/dun.c
@@ -0,0 +1,331 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <dirent.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "dund.h"
+#include "lib.h"
+
+#define PROC_BASE "/proc"
+
+static int for_each_port(int (*func)(struct rfcomm_dev_info *, unsigned long), unsigned long arg)
+{
+ struct rfcomm_dev_list_req *dl;
+ struct rfcomm_dev_info *di;
+ long r = 0;
+ int sk, i;
+
+ sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
+ if (sk < 0 ) {
+ perror("Can't open RFCOMM control socket");
+ exit(1);
+ }
+
+ dl = malloc(sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
+ if (!dl) {
+ perror("Can't allocate request memory");
+ close(sk);
+ exit(1);
+ }
+
+ dl->dev_num = RFCOMM_MAX_DEV;
+ di = dl->dev_info;
+
+ if (ioctl(sk, RFCOMMGETDEVLIST, (void *) dl) < 0) {
+ perror("Can't get device list");
+ exit(1);
+ }
+
+ for (i = 0; i < dl->dev_num; i++) {
+ r = func(di + i, arg);
+ if (r) break;
+ }
+
+ close(sk);
+ return r;
+}
+
+static int uses_rfcomm(char *path, char *dev)
+{
+ struct dirent *de;
+ DIR *dir;
+
+ dir = opendir(path);
+ if (!dir)
+ return 0;
+
+ if (chdir(path) < 0)
+ return 0;
+
+ while ((de = readdir(dir)) != NULL) {
+ char link[PATH_MAX + 1];
+ int len = readlink(de->d_name, link, sizeof(link));
+ if (len > 0) {
+ link[len] = 0;
+ if (strstr(link, dev))
+ return 1;
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+static int find_pppd(int id, pid_t *pid)
+{
+ struct dirent *de;
+ char path[PATH_MAX + 1];
+ char dev[10];
+ int empty = 1;
+ DIR *dir;
+
+ dir = opendir(PROC_BASE);
+ if (!dir) {
+ perror(PROC_BASE);
+ return -1;
+ }
+
+ sprintf(dev, "rfcomm%d", id);
+
+ *pid = 0;
+ while ((de = readdir(dir)) != NULL) {
+ empty = 0;
+ if (isdigit(de->d_name[0])) {
+ sprintf(path, "%s/%s/fd", PROC_BASE, de->d_name);
+ if (uses_rfcomm(path, dev)) {
+ *pid = atoi(de->d_name);
+ break;
+ }
+ }
+ }
+ closedir(dir);
+
+ if (empty)
+ fprintf(stderr, "%s is empty (not mounted ?)\n", PROC_BASE);
+
+ return *pid != 0;
+}
+
+static int dun_exec(char *tty, char *prog, char **args)
+{
+ int pid = fork();
+ int fd;
+
+ switch (pid) {
+ case -1:
+ return -1;
+
+ case 0:
+ break;
+
+ default:
+ return pid;
+ }
+
+ setsid();
+
+ /* Close all FDs */
+ for (fd = 3; fd < 20; fd++)
+ close(fd);
+
+ execvp(prog, args);
+
+ syslog(LOG_ERR, "Error while executing %s", prog);
+
+ exit(1);
+}
+
+static int dun_create_tty(int sk, char *tty, int size)
+{
+ struct sockaddr_rc sa;
+ struct stat st;
+ socklen_t alen;
+ int id, try = 30;
+
+ struct rfcomm_dev_req req = {
+ flags: (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP),
+ dev_id: -1
+ };
+
+ alen = sizeof(sa);
+ if (getpeername(sk, (struct sockaddr *) &sa, &alen) < 0)
+ return -1;
+ bacpy(&req.dst, &sa.rc_bdaddr);
+
+ alen = sizeof(sa);
+ if (getsockname(sk, (struct sockaddr *) &sa, &alen) < 0)
+ return -1;
+ bacpy(&req.src, &sa.rc_bdaddr);
+ req.channel = sa.rc_channel;
+
+ id = ioctl(sk, RFCOMMCREATEDEV, &req);
+ if (id < 0)
+ return id;
+
+ snprintf(tty, size, "/dev/rfcomm%d", id);
+ while (stat(tty, &st) < 0) {
+ snprintf(tty, size, "/dev/bluetooth/rfcomm/%d", id);
+ if (stat(tty, &st) < 0) {
+ snprintf(tty, size, "/dev/rfcomm%d", id);
+ if (try--) {
+ usleep(100 * 1000);
+ continue;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = id;
+ ioctl(sk, RFCOMMRELEASEDEV, &req);
+
+ return -1;
+ }
+ }
+
+ return id;
+}
+
+int dun_init(void)
+{
+ return 0;
+}
+
+int dun_cleanup(void)
+{
+ return 0;
+}
+
+static int show_conn(struct rfcomm_dev_info *di, unsigned long arg)
+{
+ pid_t pid;
+
+ if (di->state == BT_CONNECTED &&
+ (di->flags & (1<<RFCOMM_REUSE_DLC)) &&
+ (di->flags & (1<<RFCOMM_TTY_ATTACHED)) &&
+ (di->flags & (1<<RFCOMM_RELEASE_ONHUP))) {
+
+ if (find_pppd(di->id, &pid)) {
+ char dst[18];
+ ba2str(&di->dst, dst);
+
+ printf("rfcomm%d: %s channel %d pppd pid %d\n",
+ di->id, dst, di->channel, pid);
+ }
+ }
+ return 0;
+}
+
+static int kill_conn(struct rfcomm_dev_info *di, unsigned long arg)
+{
+ bdaddr_t *dst = (bdaddr_t *) arg;
+ pid_t pid;
+
+ if (di->state == BT_CONNECTED &&
+ (di->flags & (1<<RFCOMM_REUSE_DLC)) &&
+ (di->flags & (1<<RFCOMM_TTY_ATTACHED)) &&
+ (di->flags & (1<<RFCOMM_RELEASE_ONHUP))) {
+
+ if (dst && bacmp(&di->dst, dst))
+ return 0;
+
+ if (find_pppd(di->id, &pid)) {
+ if (kill(pid, SIGINT) < 0)
+ perror("Kill");
+
+ if (!dst)
+ return 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int dun_show_connections(void)
+{
+ for_each_port(show_conn, 0);
+ return 0;
+}
+
+int dun_kill_connection(uint8_t *dst)
+{
+ for_each_port(kill_conn, (unsigned long) dst);
+ return 0;
+}
+
+int dun_kill_all_connections(void)
+{
+ for_each_port(kill_conn, 0);
+ return 0;
+}
+
+int dun_open_connection(int sk, char *pppd, char **args, int wait)
+{
+ char tty[100];
+ int pid;
+
+ if (dun_create_tty(sk, tty, sizeof(tty) - 1) < 0) {
+ syslog(LOG_ERR, "RFCOMM TTY creation failed. %s(%d)", strerror(errno), errno);
+ return -1;
+ }
+
+ args[0] = "pppd";
+ args[1] = tty;
+ args[2] = "nodetach";
+
+ pid = dun_exec(tty, pppd, args);
+ if (pid < 0) {
+ syslog(LOG_ERR, "Exec failed. %s(%d)", strerror(errno), errno);
+ return -1;
+ }
+
+ if (wait) {
+ int status;
+ waitpid(pid, &status, 0);
+ /* FIXME: Check for waitpid errors */
+ }
+
+ return 0;
+}
diff --git a/utils/dund/dund.1 b/utils/dund/dund.1
new file mode 100644
index 00000000..09fb7f75
--- /dev/null
+++ b/utils/dund/dund.1
@@ -0,0 +1,72 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29.
+.TH BlueZ "1" "February 2003" "DUN daemon" "User Commands"
+.SH NAME
+dund \- BlueZ Bluetooth dial-up networking daemon
+.SH DESCRIPTION
+DUN daemon
+.SH SYNOPSIS
+dund <options> [pppd options]
+.SH OPTIONS
+.TP
+\fB\-\-show\fR \fB\-\-list\fR \fB\-l\fR
+Show active DUN connections
+.TP
+\fB\-\-listen\fR \fB\-s\fR
+Listen for DUN connections
+.TP
+\fB\-\-dialup\fR \fB\-u\fR
+Listen for dialup/telephone connections
+.TP
+\fB\-\-connect\fR \fB\-c\fR <bdaddr>
+Create DUN connection
+.TP
+\fB\-\-mrouter\fR \fB\-m\fR <bdaddr>
+Create mRouter connection
+.TP
+\fB\-\-search\fR \fB\-Q[duration]\fR
+Search and connect
+.TP
+\fB\-\-kill\fR \fB\-k\fR <bdaddr>
+Kill DUN connection
+.TP
+\fB\-\-killall\fR \fB\-K\fR
+Kill all DUN connections
+.TP
+\fB\-\-channel\fR \fB\-C\fR <channel>
+RFCOMM channel
+.TP
+\fB\-\-device\fR \fB\-i\fR <bdaddr>
+Source bdaddr
+.TP
+\fB\-\-nosdp\fR \fB\-D\fR
+Disable SDP
+.TP
+\fB\-\-auth\fR \fB\-A\fR
+Enable authentification
+.TP
+\fB\-\-encrypt\fR \fB\-E\fR
+Enable encryption
+.TP
+\fB\-\-secure\fR \fB\-S\fR
+Secure connection
+.TP
+\fB\-\-master\fR \fB\-M\fR
+Become the master of a piconet
+.TP
+\fB\-\-nodetach\fR \fB\-n\fR
+Do not become a daemon
+.TP
+\fB\-\-persist\fR \fB\-p[interval]\fR
+Persist mode
+.TP
+\fB\-\-pppd\fR \fB\-d\fR <pppd>
+Location of the PPP daemon (pppd)
+.TP
+\fB\-\-msdun\fR \fB\-X\fR [timeo]
+Enable Microsoft dialup networking support
+.TP
+\fB\-\-activesync\fR \fB\-a\fR
+Enable Microsoft ActiveSync networking
+.TP
+\fB\-\-cache\fR \fB\-C\fR [valid]
+Enable address cache
diff --git a/utils/dund/dund.h b/utils/dund/dund.h
new file mode 100644
index 00000000..00008578
--- /dev/null
+++ b/utils/dund/dund.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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
+ *
+ */
+
+/* DUN scripts & commands */
+#define DUN_CONFIG_DIR "/etc/bluetooth/dun"
+
+#define DUN_DEFAULT_CHANNEL 1
+
+#define DUN_MAX_PPP_OPTS 40
+
+/* DUN types */
+#define LANACCESS 0
+#define MROUTER 1
+#define ACTIVESYNC 2
+#define DIALUP 3
+
+/* DUN functions */
+int dun_init(void);
+int dun_cleanup(void);
+
+int dun_show_connections(void);
+int dun_kill_connection(uint8_t *dst);
+int dun_kill_all_connections(void);
+
+int dun_open_connection(int sk, char *pppd, char **pppd_opts, int wait);
+
+/* SDP functions */
+int dun_sdp_register(bdaddr_t *device, uint8_t channel, int type);
+void dun_sdp_unregister(void);
+int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel, int type);
diff --git a/utils/dund/lib.h b/utils/dund/lib.h
new file mode 100644
index 00000000..e4b6e401
--- /dev/null
+++ b/utils/dund/lib.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <signal.h>
+
+#ifndef min
+#define min(a,b) ( (a)<(b) ? (a):(b) )
+#endif
+
+/* IO cancelation */
+extern volatile sig_atomic_t __io_canceled;
+
+static inline void io_init(void)
+{
+ __io_canceled = 0;
+}
+
+static inline void io_cancel(void)
+{
+ __io_canceled = 1;
+}
+
+/* Read exactly len bytes (Signal safe)*/
+static inline int read_n(int fd, char *buf, int len)
+{
+ register int t = 0, w;
+
+ while (!__io_canceled && len > 0) {
+ if ((w = read(fd, buf, len)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ if (!w)
+ return 0;
+ len -= w;
+ buf += w;
+ t += w;
+ }
+
+ return t;
+}
+
+/* Write exactly len bytes (Signal safe)*/
+static inline int write_n(int fd, char *buf, int len)
+{
+ register int t = 0, w;
+
+ while (!__io_canceled && len > 0) {
+ if ((w = write(fd, buf, len)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ if (!w)
+ return 0;
+ len -= w;
+ buf += w;
+ t += w;
+ }
+
+ return t;
+}
+
+int ms_dun(int fd, int server, int timeo);
diff --git a/utils/dund/main.c b/utils/dund/main.c
new file mode 100644
index 00000000..b14adce0
--- /dev/null
+++ b/utils/dund/main.c
@@ -0,0 +1,635 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#include <getopt.h>
+
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/rfcomm.h>
+
+#include "dund.h"
+#include "lib.h"
+
+volatile sig_atomic_t __io_canceled;
+
+/* MS dialup networking support (i.e. CLIENT / CLIENTSERVER thing) */
+static int msdun = 0;
+
+static char *pppd = "/usr/sbin/pppd";
+static char *pppd_opts[DUN_MAX_PPP_OPTS] =
+ {
+ /* First 3 are reserved */
+ "", "", "",
+ "noauth",
+ "noipdefault",
+ NULL
+ };
+
+static int detach = 1;
+static int persist;
+static int use_sdp = 1;
+static int auth;
+static int encrypt;
+static int secure;
+static int master;
+static int type = LANACCESS;
+static int search_duration = 10;
+static uint use_cache;
+
+static int channel;
+
+static struct {
+ uint valid;
+ char dst[40];
+ bdaddr_t bdaddr;
+ int channel;
+} cache;
+
+static bdaddr_t src_addr = *BDADDR_ANY;
+static int src_dev = -1;
+
+volatile int terminate;
+
+enum {
+ NONE,
+ SHOW,
+ LISTEN,
+ CONNECT,
+ KILL
+} modes;
+
+static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter);
+
+static int do_listen(void)
+{
+ struct sockaddr_rc sa;
+ int sk, lm;
+
+ if (type == MROUTER) {
+ if (!cache.valid)
+ return -1;
+
+ if (create_connection(cache.dst, &cache.bdaddr, type) < 0) {
+ syslog(LOG_ERR, "Cannot connect to mRouter device. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+ }
+
+ if (!channel)
+ channel = DUN_DEFAULT_CHANNEL;
+
+ if (use_sdp)
+ dun_sdp_register(&src_addr, channel, type);
+
+ if (type == MROUTER)
+ syslog(LOG_INFO, "Waiting for mRouter callback on channel %d", channel);
+
+ /* Create RFCOMM socket */
+ sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ sa.rc_family = AF_BLUETOOTH;
+ sa.rc_channel = channel;
+ sa.rc_bdaddr = src_addr;
+
+ if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
+ syslog(LOG_ERR, "Bind failed. %s(%d)", strerror(errno), errno);
+ return -1;
+ }
+
+ /* Set link mode */
+ lm = 0;
+ if (master)
+ lm |= RFCOMM_LM_MASTER;
+ if (auth)
+ lm |= RFCOMM_LM_AUTH;
+ if (encrypt)
+ lm |= RFCOMM_LM_ENCRYPT;
+ if (secure)
+ lm |= RFCOMM_LM_SECURE;
+
+ if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
+ syslog(LOG_ERR, "Failed to set link mode. %s(%d)", strerror(errno), errno);
+ return -1;
+ }
+
+ listen(sk, 10);
+
+ while (!terminate) {
+ socklen_t alen = sizeof(sa);
+ int nsk;
+ char ba[40];
+ char ch[10];
+
+ nsk = accept(sk, (struct sockaddr *) &sa, &alen);
+ if (nsk < 0) {
+ syslog(LOG_ERR, "Accept failed. %s(%d)", strerror(errno), errno);
+ continue;
+ }
+
+ switch (fork()) {
+ case 0:
+ break;
+ case -1:
+ syslog(LOG_ERR, "Fork failed. %s(%d)", strerror(errno), errno);
+ default:
+ close(nsk);
+ if (type == MROUTER) {
+ close(sk);
+ terminate = 1;
+ }
+ continue;
+ }
+
+ close(sk);
+
+ if (msdun && ms_dun(nsk, 1, msdun) < 0) {
+ syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
+ exit(0);
+ }
+
+ ba2str(&sa.rc_bdaddr, ba);
+ sprintf(ch, "%d", channel);
+
+ /* Setup environment */
+ setenv("DUN_BDADDR", ba, 1);
+ setenv("DUN_CHANNEL", ch, 1);
+
+ if (!dun_open_connection(nsk, pppd, pppd_opts, 0))
+ syslog(LOG_INFO, "New connection from %s", ba);
+
+ close(nsk);
+ exit(0);
+ }
+
+ if (use_sdp)
+ dun_sdp_unregister();
+ return 0;
+}
+
+/* Connect and initiate RFCOMM session
+ * Returns:
+ * -1 - critical error (exit persist mode)
+ * 1 - non critical error
+ * 0 - success
+ */
+static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter)
+{
+ struct sockaddr_rc sa;
+ int sk, err = 0, ch;
+
+ if (use_cache && cache.valid && cache.channel) {
+ /* Use cached channel */
+ ch = cache.channel;
+
+ } else if (!channel) {
+ syslog(LOG_INFO, "Searching for %s on %s", mrouter ? "SP" : "LAP", dst);
+
+ if (dun_sdp_search(&src_addr, bdaddr, &ch, mrouter) <= 0)
+ return 0;
+ } else
+ ch = channel;
+
+ syslog(LOG_INFO, "Connecting to %s channel %d", dst, ch);
+
+ sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ sa.rc_family = AF_BLUETOOTH;
+ sa.rc_channel = 0;
+ sa.rc_bdaddr = src_addr;
+
+ if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)))
+ syslog(LOG_ERR, "Bind failed. %s(%d)",
+ strerror(errno), errno);
+
+ sa.rc_channel = ch;
+ sa.rc_bdaddr = *bdaddr;
+
+ if (!connect(sk, (struct sockaddr *) &sa, sizeof(sa)) ) {
+ if (mrouter) {
+ sleep(1);
+ close(sk);
+ return 0;
+ }
+
+ syslog(LOG_INFO, "Connection established");
+
+ if (msdun && ms_dun(sk, 0, msdun) < 0) {
+ syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
+ err = 1;
+ goto out;
+ }
+
+ if (!dun_open_connection(sk, pppd, pppd_opts, (persist > 0)))
+ err = 0;
+ else
+ err = 1;
+ } else {
+ syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
+ dst, strerror(errno), errno);
+ err = 1;
+ }
+
+out:
+ if (use_cache) {
+ if (!err) {
+ /* Succesesful connection, validate cache */
+ strcpy(cache.dst, dst);
+ bacpy(&cache.bdaddr, bdaddr);
+ cache.channel = ch;
+ cache.valid = use_cache;
+ } else {
+ cache.channel = 0;
+ cache.valid--;
+ }
+ }
+
+ close(sk);
+ return err;
+}
+
+/* Search and connect
+ * Returns:
+ * -1 - critical error (exit persist mode)
+ * 1 - non critical error
+ * 0 - success
+ */
+static int do_connect(void)
+{
+ inquiry_info *ii;
+ int reconnect = 0;
+ int i, n, r = 0;
+
+ do {
+ if (reconnect)
+ sleep(persist);
+ reconnect = 1;
+
+ if (cache.valid) {
+ /* Use cached bdaddr */
+ r = create_connection(cache.dst, &cache.bdaddr, 0);
+ if (r < 0) {
+ terminate = 1;
+ break;
+ }
+ continue;
+ }
+
+ syslog(LOG_INFO, "Inquiring");
+
+ /* FIXME: Should we use non general LAP here ? */
+
+ ii = NULL;
+ n = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0);
+ if (n < 0) {
+ syslog(LOG_ERR, "Inquiry failed. %s(%d)", strerror(errno), errno);
+ continue;
+ }
+
+ for (i = 0; i < n; i++) {
+ char dst[40];
+ ba2str(&ii[i].bdaddr, dst);
+
+ r = create_connection(dst, &ii[i].bdaddr, 0);
+ if (r < 0) {
+ terminate = 1;
+ break;
+ }
+ }
+ bt_free(ii);
+ } while (!terminate && persist);
+
+ return r;
+}
+
+static void do_show(void)
+{
+ dun_show_connections();
+}
+
+static void do_kill(char *dst)
+{
+ if (dst) {
+ bdaddr_t ba;
+ str2ba(dst, &ba);
+ dun_kill_connection((void *) &ba);
+ } else
+ dun_kill_all_connections();
+}
+
+void sig_hup(int sig)
+{
+ return;
+}
+
+void sig_term(int sig)
+{
+ io_cancel();
+ terminate = 1;
+}
+
+static struct option main_lopts[] = {
+ { "help", 0, 0, 'h' },
+ { "listen", 0, 0, 's' },
+ { "connect", 1, 0, 'c' },
+ { "search", 2, 0, 'Q' },
+ { "kill", 1, 0, 'k' },
+ { "killall", 0, 0, 'K' },
+ { "channel", 1, 0, 'P' },
+ { "device", 1, 0, 'i' },
+ { "nosdp", 0, 0, 'D' },
+ { "list", 0, 0, 'l' },
+ { "show", 0, 0, 'l' },
+ { "nodetach", 0, 0, 'n' },
+ { "persist", 2, 0, 'p' },
+ { "auth", 0, 0, 'A' },
+ { "encrypt", 0, 0, 'E' },
+ { "secure", 0, 0, 'S' },
+ { "master", 0, 0, 'M' },
+ { "cache", 0, 0, 'C' },
+ { "pppd", 1, 0, 'd' },
+ { "msdun", 2, 0, 'X' },
+ { "activesync", 0, 0, 'a' },
+ { "mrouter", 1, 0, 'm' },
+ { "dialup", 0, 0, 'u' },
+ { 0, 0, 0, 0 }
+};
+
+static char main_sopts[] = "hsc:k:Kr:i:lnp::DQ::AESMP:C::P:Xam:u";
+
+static char main_help[] =
+ "Bluetooth LAP (LAN Access over PPP) daemon version " VERSION " \n"
+ "Usage:\n"
+ "\tdund <options> [pppd options]\n"
+ "Options:\n"
+ "\t--show --list -l Show active LAP connections\n"
+ "\t--listen -s Listen for LAP connections\n"
+ "\t--dialup -u Pretend to be a dialup/telephone\n"
+ "\t--connect -c <bdaddr> Create LAP connection\n"
+ "\t--mrouter -m <bdaddr> Create mRouter connection\n"
+ "\t--search -Q[duration] Search and connect\n"
+ "\t--kill -k <bdaddr> Kill LAP connection\n"
+ "\t--killall -K Kill all LAP connections\n"
+ "\t--channel -P <channel> RFCOMM channel\n"
+ "\t--device -i <bdaddr> Source bdaddr\n"
+ "\t--nosdp -D Disable SDP\n"
+ "\t--auth -A Enable authentication\n"
+ "\t--encrypt -E Enable encryption\n"
+ "\t--secure -S Secure connection\n"
+ "\t--master -M Become the master of a piconet\n"
+ "\t--nodetach -n Do not become a daemon\n"
+ "\t--persist -p[interval] Persist mode\n"
+ "\t--pppd -d <pppd> Location of the PPP daemon (pppd)\n"
+ "\t--msdun -X[timeo] Enable Microsoft dialup networking support\n"
+ "\t--activesync -a Enable Microsoft ActiveSync networking\n"
+ "\t--cache -C[valid] Enable address cache\n";
+
+int main(int argc, char *argv[])
+{
+ char *dst = NULL, *src = NULL;
+ struct sigaction sa;
+ int mode = NONE;
+ int opt;
+
+ while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
+ switch(opt) {
+ case 'l':
+ mode = SHOW;
+ detach = 0;
+ break;
+
+ case 's':
+ mode = LISTEN;
+ type = LANACCESS;
+ break;
+
+ case 'c':
+ mode = CONNECT;
+ dst = strdup(optarg);
+ break;
+
+ case 'Q':
+ mode = CONNECT;
+ dst = NULL;
+ if (optarg)
+ search_duration = atoi(optarg);
+ break;
+
+ case 'k':
+ mode = KILL;
+ detach = 0;
+ dst = strdup(optarg);
+ break;
+
+ case 'K':
+ mode = KILL;
+ detach = 0;
+ dst = NULL;
+ break;
+
+ case 'P':
+ channel = atoi(optarg);
+ break;
+
+ case 'i':
+ src = strdup(optarg);
+ break;
+
+ case 'D':
+ use_sdp = 0;
+ break;
+
+ case 'A':
+ auth = 1;
+ break;
+
+ case 'E':
+ encrypt = 1;
+ break;
+
+ case 'S':
+ secure = 1;
+ break;
+
+ case 'M':
+ master = 1;
+ break;
+
+ case 'n':
+ detach = 0;
+ break;
+
+ case 'p':
+ if (optarg)
+ persist = atoi(optarg);
+ else
+ persist = 5;
+ break;
+
+ case 'C':
+ if (optarg)
+ use_cache = atoi(optarg);
+ else
+ use_cache = 2;
+ break;
+
+ case 'd':
+ pppd = strdup(optarg);
+ break;
+
+ case 'X':
+ if (optarg)
+ msdun = atoi(optarg);
+ else
+ msdun = 10;
+ break;
+
+ case 'a':
+ msdun = 10;
+ type = ACTIVESYNC;
+ break;
+
+ case 'm':
+ mode = LISTEN;
+ dst = strdup(optarg);
+ type = MROUTER;
+ break;
+
+ case 'u':
+ mode = LISTEN;
+ type = DIALUP;
+ break;
+
+ case 'h':
+ default:
+ printf(main_help);
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* The rest is pppd options */
+ if (argc > 0) {
+ for (opt = 3; argc && opt < DUN_MAX_PPP_OPTS; argc--, opt++)
+ pppd_opts[opt] = *argv++;
+ pppd_opts[opt] = NULL;
+ }
+
+ io_init();
+
+ if (dun_init())
+ return -1;
+
+ /* Check non daemon modes first */
+ switch (mode) {
+ case SHOW:
+ do_show();
+ return 0;
+
+ case KILL:
+ do_kill(dst);
+ return 0;
+
+ case NONE:
+ printf(main_help);
+ return 0;
+ }
+
+ /* Initialize signals */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ if (detach && daemon(0, 0)) {
+ perror("Can't start daemon");
+ exit(1);
+ }
+
+ openlog("dund", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
+ syslog(LOG_INFO, "Bluetooth DUN daemon version %s", VERSION);
+
+ if (src) {
+ src_dev = hci_devid(src);
+ if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
+ syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno);
+ return -1;
+ }
+ }
+
+ if (dst) {
+ strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
+ str2ba(dst, &cache.bdaddr);
+
+ /* Disable cache invalidation */
+ use_cache = cache.valid = ~0;
+ }
+
+ switch (mode) {
+ case CONNECT:
+ do_connect();
+ break;
+
+ case LISTEN:
+ do_listen();
+ break;
+ }
+
+ return 0;
+}
diff --git a/utils/dund/msdun.c b/utils/dund/msdun.c
new file mode 100644
index 00000000..1ef559f1
--- /dev/null
+++ b/utils/dund/msdun.c
@@ -0,0 +1,151 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <setjmp.h>
+#include <string.h>
+
+#include "lib.h"
+
+#define MS_PPP 2
+#define MS_SUCCESS 1
+#define MS_FAILED -1
+#define MS_TIMEOUT -2
+
+static sigjmp_buf jmp;
+static int retry;
+static int timeout;
+
+static void sig_alarm(int sig)
+{
+ siglongjmp(jmp, MS_TIMEOUT);
+}
+
+static int w4_str(int fd, char *str)
+{
+ char buf[40];
+ int r, len = 0;
+
+ while (1) {
+ r = read(fd, buf + len, sizeof(buf) - len - 1);
+ if (r < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ break;
+ }
+ if (!r)
+ break;
+
+ len += r;
+
+ if (len < strlen(str))
+ continue;
+ buf[len] = 0;
+
+ if (strstr(buf, str))
+ return MS_SUCCESS;
+
+ /* Detect PPP */
+ if (strchr(buf, '~'))
+ return MS_PPP;
+ }
+ return MS_FAILED;
+}
+
+static int ms_server(int fd)
+{
+ switch (w4_str(fd, "CLIENT")) {
+ case MS_SUCCESS:
+ write_n(fd, "CLIENTSERVER", 12);
+ case MS_PPP:
+ return MS_SUCCESS;
+ default:
+ return MS_FAILED;
+ }
+}
+
+static int ms_client(int fd)
+{
+ write_n(fd, "CLIENT", 6);
+ return w4_str(fd, "CLIENTSERVER");
+}
+
+int ms_dun(int fd, int server, int timeo)
+{
+ sig_t osig;
+
+ retry = 4;
+ timeout = timeo;
+
+ if (!server)
+ timeout /= retry;
+
+ osig = signal(SIGALRM, sig_alarm);
+
+ while (1) {
+ int r = sigsetjmp(jmp, 1);
+ if (r) {
+ if (r == MS_TIMEOUT && !server && --retry)
+ continue;
+
+ alarm(0);
+ signal(SIGALRM, osig);
+
+ switch (r) {
+ case MS_SUCCESS:
+ case MS_PPP:
+ errno = 0;
+ return 0;
+
+ case MS_FAILED:
+ errno = EPROTO;
+ break;
+
+ case MS_TIMEOUT:
+ errno = ETIMEDOUT;
+ break;
+ }
+ return -1;
+ }
+
+ alarm(timeout);
+
+ if (server)
+ r = ms_server(fd);
+ else
+ r = ms_client(fd);
+
+ siglongjmp(jmp, r);
+ }
+}
diff --git a/utils/dund/sdp.c b/utils/dund/sdp.c
new file mode 100644
index 00000000..f2c42c5a
--- /dev/null
+++ b/utils/dund/sdp.c
@@ -0,0 +1,208 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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 <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "dund.h"
+
+static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
+ 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
+
+static sdp_record_t *record;
+static sdp_session_t *session;
+
+void dun_sdp_unregister(void)
+{
+ if (record && sdp_record_unregister(session, record))
+ syslog(LOG_ERR, "Service record unregistration failed.");
+ sdp_close(session);
+}
+
+int dun_sdp_register(bdaddr_t *device, uint8_t channel, int type)
+{
+ sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
+ uuid_t root_uuid, l2cap, rfcomm, dun;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *proto[2];
+ int status;
+
+ session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
+ if (!session) {
+ syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ record = sdp_record_alloc();
+ if (!record) {
+ syslog(LOG_ERR, "Failed to alloc service record");
+ return -1;
+ }
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(NULL, &l2cap);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+ proto[1] = sdp_list_append(NULL, &rfcomm);
+ proto[1] = sdp_list_append(proto[1], sdp_data_alloc(SDP_UINT8, &channel));
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ switch (type) {
+ case MROUTER:
+ sdp_uuid16_create(&dun, SERIAL_PORT_SVCLASS_ID);
+ break;
+ case ACTIVESYNC:
+ sdp_uuid128_create(&dun, (void *) async_uuid);
+ break;
+ case DIALUP:
+ sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
+ break;
+ default:
+ sdp_uuid16_create(&dun, LAN_ACCESS_SVCLASS_ID);
+ break;
+ }
+
+ svclass = sdp_list_append(NULL, &dun);
+ sdp_set_service_classes(record, svclass);
+
+ switch (type) {
+ case LANACCESS:
+ sdp_uuid16_create(&profile[0].uuid, LAN_ACCESS_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+ break;
+ case DIALUP:
+ sdp_uuid16_create(&profile[0].uuid, DIALUP_NET_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+ break;
+ }
+
+ switch (type) {
+ case MROUTER:
+ sdp_set_info_attr(record, "mRouter", NULL, NULL);
+ break;
+ case ACTIVESYNC:
+ sdp_set_info_attr(record, "ActiveSync", NULL, NULL);
+ break;
+ case DIALUP:
+ sdp_set_info_attr(record, "Dialup Networking", NULL, NULL);
+ break;
+ default:
+ sdp_set_info_attr(record, "LAN Access Point", NULL, NULL);
+ break;
+ }
+
+ status = sdp_device_record_register(session, device, record, 0);
+ if (status) {
+ syslog(LOG_ERR, "SDP registration failed.");
+ sdp_record_free(record);
+ record = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel, int type)
+{
+ sdp_session_t *s;
+ sdp_list_t *srch, *attrs, *rsp;
+ uuid_t svclass;
+ uint16_t attr;
+ int err;
+
+ s = sdp_connect(src, dst, 0);
+ if (!s) {
+ syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ switch (type) {
+ case MROUTER:
+ sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
+ break;
+ case ACTIVESYNC:
+ sdp_uuid128_create(&svclass, (void *) async_uuid);
+ break;
+ case DIALUP:
+ sdp_uuid16_create(&svclass, DIALUP_NET_SVCLASS_ID);
+ break;
+ default:
+ sdp_uuid16_create(&svclass, LAN_ACCESS_SVCLASS_ID);
+ break;
+ }
+
+ srch = sdp_list_append(NULL, &svclass);
+
+ attr = SDP_ATTR_PROTO_DESC_LIST;
+ attrs = sdp_list_append(NULL, &attr);
+
+ err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+
+ sdp_close(s);
+
+ if (err)
+ return 0;
+
+ for(; rsp; rsp = rsp->next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
+ sdp_list_t *protos;
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ int ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ if (ch > 0) {
+ *channel = ch;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/utils/eglib/Makefile.am b/utils/eglib/Makefile.am
new file mode 100644
index 00000000..e6166090
--- /dev/null
+++ b/utils/eglib/Makefile.am
@@ -0,0 +1,8 @@
+
+if !GLIB
+noinst_LTLIBRARIES = libeglib.la
+
+libeglib_la_SOURCES = glib.h gmain.h gmain.c gmodule.h gmodule.c
+endif
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/eglib/Makefile.in b/utils/eglib/Makefile.in
new file mode 100644
index 00000000..e16adc77
--- /dev/null
+++ b/utils/eglib/Makefile.in
@@ -0,0 +1,459 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = eglib
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libeglib_la_LIBADD =
+am__libeglib_la_SOURCES_DIST = glib.h gmain.h gmain.c gmodule.h \
+ gmodule.c
+@GLIB_FALSE@am_libeglib_la_OBJECTS = gmain.lo gmodule.lo
+libeglib_la_OBJECTS = $(am_libeglib_la_OBJECTS)
+@GLIB_FALSE@am_libeglib_la_rpath =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libeglib_la_SOURCES)
+DIST_SOURCES = $(am__libeglib_la_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@GLIB_FALSE@noinst_LTLIBRARIES = libeglib.la
+@GLIB_FALSE@libeglib_la_SOURCES = glib.h gmain.h gmain.c gmodule.h gmodule.c
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu eglib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu eglib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libeglib.la: $(libeglib_la_OBJECTS) $(libeglib_la_DEPENDENCIES)
+ $(LINK) $(am_libeglib_la_rpath) $(libeglib_la_OBJECTS) $(libeglib_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gmain.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gmodule.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/eglib/glib.h b/utils/eglib/glib.h
new file mode 100644
index 00000000..5600a33e
--- /dev/null
+++ b/utils/eglib/glib.h
@@ -0,0 +1 @@
+#include <gmain.h>
diff --git a/utils/eglib/gmain.c b/utils/eglib/gmain.c
new file mode 100644
index 00000000..1ca3d67a
--- /dev/null
+++ b/utils/eglib/gmain.c
@@ -0,0 +1,1976 @@
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <dirent.h>
+
+#include <gmain.h>
+
+struct timeout {
+ guint id;
+ guint interval;
+ struct timeval expiration;
+ gpointer data;
+ GSourceFunc function;
+};
+
+struct _GIOChannel {
+ int fd;
+ int ref_count;
+ gboolean closed;
+ gboolean close_on_unref;
+};
+
+struct child_watch {
+ guint id;
+ GPid pid;
+ GChildWatchFunc function;
+ gpointer user_data;
+};
+
+struct _GMainContext {
+ guint next_id;
+ glong next_timeout;
+
+ GSList *timeouts;
+ GSList *proc_timeouts;
+ gboolean timeout_lock;
+
+ GSList *io_watches;
+ GSList *proc_io_watches;
+ gboolean io_lock;
+
+ GSList *child_watches;
+ GSList *proc_child_watches;
+ gboolean child_lock;
+};
+
+struct _GMainLoop {
+ gboolean is_running;
+ GMainContext *context;
+};
+
+struct _GDir
+{
+ DIR *dirp;
+};
+
+GIOError g_io_channel_read(GIOChannel *channel, gchar *buf, gsize count,
+ gsize *bytes_read)
+{
+ int fd = channel->fd;
+ gssize result;
+
+ if (channel->closed)
+ return G_IO_STATUS_ERROR;
+
+ /* At least according to the Debian manpage for read */
+ if (count > SSIZE_MAX)
+ count = SSIZE_MAX;
+
+retry:
+ result = read (fd, buf, count);
+
+ if (result < 0) {
+ *bytes_read = 0;
+
+ switch (errno) {
+#ifdef EINTR
+ case EINTR:
+ goto retry;
+#endif
+#ifdef EAGAIN
+ case EAGAIN:
+ return G_IO_STATUS_AGAIN;
+#endif
+ default:
+ return G_IO_STATUS_ERROR;
+ }
+ }
+
+ *bytes_read = result;
+
+ return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
+}
+
+GIOError g_io_channel_write(GIOChannel *channel, const gchar *buf, gsize count,
+ gsize *bytes_written)
+{
+ int fd = channel->fd;
+ gssize result;
+
+ if (channel->closed)
+ return G_IO_STATUS_ERROR;
+
+ /* At least according to the Debian manpage for read */
+ if (count > SSIZE_MAX)
+ count = SSIZE_MAX;
+
+retry:
+ result = write(fd, buf, count);
+
+ if (result < 0) {
+ *bytes_written = 0;
+
+ switch (errno) {
+#ifdef EINTR
+ case EINTR:
+ goto retry;
+#endif
+#ifdef EAGAIN
+ case EAGAIN:
+ return G_IO_STATUS_AGAIN;
+#endif
+ default:
+ return G_IO_STATUS_ERROR;
+ }
+ }
+
+ *bytes_written = result;
+
+ return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
+}
+
+void g_io_channel_close(GIOChannel *channel)
+{
+ if (!channel || channel->closed)
+ return;
+
+ close(channel->fd);
+
+ channel->closed = TRUE;
+}
+
+void g_io_channel_unref(GIOChannel *channel)
+{
+ if (!channel)
+ return;
+
+ if (--channel->ref_count > 0)
+ return;
+
+ if (channel->close_on_unref && channel->fd >= 0)
+ g_io_channel_close(channel);
+
+ g_free(channel);
+}
+
+GIOChannel *g_io_channel_ref(GIOChannel *channel)
+{
+ channel->ref_count++;
+ return channel;
+}
+
+GIOChannel *g_io_channel_unix_new(int fd)
+{
+ GIOChannel *channel;
+
+ channel = g_new0(GIOChannel, 1);
+
+ channel->fd = fd;
+ channel->ref_count = 1;
+
+ return channel;
+}
+
+void g_io_channel_set_close_on_unref(GIOChannel *channel, gboolean do_close)
+{
+ channel->close_on_unref = do_close;
+}
+
+gint g_io_channel_unix_get_fd(GIOChannel *channel)
+{
+ if (channel->closed)
+ return -1;
+
+ return channel->fd;
+}
+
+static int set_flags(int fd, long flags)
+{
+ long arg;
+
+ arg = fcntl(fd, F_GETFL);
+ if (arg < 0)
+ return -errno;
+
+ /* Return if already set */
+ if ((arg & flags) == flags)
+ return 0;
+
+ arg |= flags;
+ if (fcntl(fd, F_SETFL, arg) < 0)
+ return -errno;
+
+ return 0;
+}
+
+GIOStatus g_io_channel_set_flags(GIOChannel *channel, GIOFlags flags,
+ GError **error)
+{
+ int err, fd;
+ long fd_flags = 0;
+
+ if (!channel || channel->closed)
+ return G_IO_STATUS_ERROR;
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ if (flags & G_IO_FLAG_APPEND)
+ fd_flags |= O_APPEND;
+ if (flags & G_IO_FLAG_NONBLOCK)
+ fd_flags |= O_NONBLOCK;
+
+ err = set_flags(fd, fd_flags);
+ if (err < 0) {
+ if (error)
+ g_set_error(error, 0, 0, "Unable to set flags: %s",
+ strerror(-err));
+ return G_IO_STATUS_ERROR;
+ }
+
+ return G_IO_STATUS_NORMAL;
+}
+
+struct io_watch {
+ guint id;
+ GIOChannel *channel;
+ gint priority;
+ GIOCondition condition;
+ short *revents;
+ GIOFunc func;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+static GMainContext *default_context = NULL;
+
+static void watch_free(struct io_watch *watch)
+{
+ if (watch->destroy)
+ watch->destroy(watch->user_data);
+ g_io_channel_unref(watch->channel);
+ g_free(watch);
+}
+
+static GMainContext *g_main_context_default()
+{
+ if (default_context)
+ return default_context;
+
+ default_context = g_new0(GMainContext, 1);
+
+ default_context->next_timeout = -1;
+ default_context->next_id = 1;
+
+ return default_context;
+}
+
+static gboolean g_io_remove_watch(GMainContext *context, guint id)
+{
+ GSList *l;
+ struct io_watch *w;
+
+ for (l = context->io_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->io_watches = g_slist_remove(context->io_watches, w);
+ watch_free(w);
+
+ return TRUE;
+ }
+
+ for (l = context->proc_io_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->proc_io_watches = g_slist_remove(context->proc_io_watches, w);
+ watch_free(w);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean g_timeout_remove(GMainContext *context, const guint id)
+{
+ GSList *l;
+ struct timeout *t;
+
+ l = context->timeouts;
+
+ while (l) {
+ t = l->data;
+ l = l->next;
+
+ if (t->id != id)
+ continue;
+
+ context->timeouts = g_slist_remove(context->timeouts, t);
+ g_free(t);
+
+ return TRUE;
+ }
+
+ l = context->proc_timeouts;
+
+ while (l) {
+ t = l->data;
+ l = l->next;
+
+ if (t->id != id)
+ continue;
+
+ context->proc_timeouts = g_slist_remove(context->proc_timeouts, t);
+ g_free(t);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int watch_prio_cmp(struct io_watch *w1, struct io_watch *w2)
+{
+ return w1->priority - w2->priority;
+}
+
+#define watch_list_add(l, w) g_slist_insert_sorted((l), (w), (GCompareFunc) watch_prio_cmp)
+
+guint g_io_add_watch_full(GIOChannel *channel, gint priority,
+ GIOCondition condition, GIOFunc func,
+ gpointer user_data, GDestroyNotify notify)
+{
+ struct io_watch *watch;
+ GMainContext *context = g_main_context_default();
+
+ watch = g_new(struct io_watch, 1);
+
+ watch->id = context->next_id++;
+ watch->channel = g_io_channel_ref(channel);
+ watch->priority = priority;
+ watch->condition = condition;
+ watch->func = func;
+ watch->user_data = user_data;
+ watch->destroy = notify;
+
+ if (context->io_lock)
+ context->proc_io_watches = watch_list_add(context->proc_io_watches, watch);
+ else
+ context->io_watches = watch_list_add(context->io_watches, watch);
+
+ return watch->id;
+}
+
+guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,
+ GIOFunc func, gpointer user_data)
+{
+ return g_io_add_watch_full(channel, 0, condition,
+ func, user_data, NULL);
+}
+
+GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running)
+{
+ GMainLoop *ml;
+
+ if (!context)
+ context = g_main_context_default();
+
+ ml = g_new0(GMainLoop, 1);
+
+ ml->context = context;
+ ml->is_running = is_running;
+
+ return ml;
+}
+
+static void timeout_handlers_prepare(GMainContext *context)
+{
+ GSList *l;
+ struct timeval tv;
+ glong msec, timeout = LONG_MAX;
+
+ gettimeofday(&tv, NULL);
+
+ for (l = context->timeouts; l != NULL; l = l->next) {
+ struct timeout *t = l->data;
+
+ /* calculate the remainning time */
+ msec = (t->expiration.tv_sec - tv.tv_sec) * 1000 +
+ (t->expiration.tv_usec - tv.tv_usec) / 1000;
+ if (msec < 0)
+ msec = 0;
+
+ timeout = MIN_TIMEOUT(timeout, msec);
+ }
+
+ /* set to min value found or NO timeout */
+ context->next_timeout = (timeout != LONG_MAX ? timeout : -1);
+}
+
+static int ptr_cmp(const void *t1, const void *t2)
+{
+ return t1 - t2;
+}
+
+static void timeout_handlers_check(GMainContext *context)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ context->timeout_lock = TRUE;
+
+ while (context->timeouts) {
+ struct timeout *t = context->timeouts->data;
+ glong secs, msecs;
+ gboolean ret;
+
+ if (timercmp(&tv, &t->expiration, <)) {
+ context->timeouts = g_slist_remove(context->timeouts, t);
+ context->proc_timeouts = g_slist_append(context->proc_timeouts, t);
+ continue;
+ }
+
+ ret = t->function(t->data);
+
+ /* Check if the handler was removed/freed by the callback
+ * function */
+ if (!g_slist_find_custom(context->timeouts, t, ptr_cmp))
+ continue;
+
+ context->timeouts = g_slist_remove(context->timeouts, t);
+
+ if (!ret) {
+ g_free(t);
+ continue;
+ }
+
+ /* update the next expiration time */
+ secs = t->interval / 1000;
+ msecs = t->interval - secs * 1000;
+
+ t->expiration.tv_sec = tv.tv_sec + secs;
+ t->expiration.tv_usec = tv.tv_usec + msecs * 1000;
+ if (t->expiration.tv_usec >= 1000000) {
+ t->expiration.tv_usec -= 1000000;
+ t->expiration.tv_sec++;
+ }
+
+ context->proc_timeouts = g_slist_append(context->proc_timeouts, t);
+ }
+
+ context->timeouts = context->proc_timeouts;
+ context->proc_timeouts = NULL;
+ context->timeout_lock = FALSE;
+}
+
+void g_main_loop_run(GMainLoop *loop)
+{
+ int open_max = sysconf(_SC_OPEN_MAX);
+ struct pollfd *ufds;
+ GMainContext *context = loop->context;
+
+ ufds = g_new(struct pollfd, open_max);
+
+ loop->is_running = TRUE;
+
+ while (loop->is_running) {
+ int nfds;
+ GSList *l;
+ struct io_watch *w;
+
+ for (nfds = 0, l = context->io_watches; l != NULL; l = l->next, nfds++) {
+ w = l->data;
+ ufds[nfds].fd = w->channel->fd;
+ ufds[nfds].events = w->condition;
+ ufds[nfds].revents = 0;
+ w->revents = &ufds[nfds].revents;
+ }
+
+ /* calculate the next timeout */
+ timeout_handlers_prepare(context);
+
+ if (poll(ufds, nfds, context->next_timeout) < 0)
+ continue;
+
+ context->io_lock = TRUE;
+
+ while (context->io_watches) {
+ gboolean ret;
+
+ w = context->io_watches->data;
+
+ if (!*w->revents) {
+ context->io_watches = g_slist_remove(context->io_watches, w);
+ context->proc_io_watches = watch_list_add(context->proc_io_watches, w);
+ continue;
+ }
+
+ ret = w->func(w->channel, *w->revents, w->user_data);
+
+ /* Check if the watch was removed/freed by the callback
+ * function */
+ if (!g_slist_find_custom(context->io_watches, w, ptr_cmp))
+ continue;
+
+ context->io_watches = g_slist_remove(context->io_watches, w);
+
+ if (!ret) {
+ watch_free(w);
+ continue;
+ }
+
+ context->proc_io_watches = watch_list_add(context->proc_io_watches, w);
+ }
+
+ context->io_watches = context->proc_io_watches;
+ context->proc_io_watches = NULL;
+ context->io_lock = FALSE;
+
+ /* check expired timers */
+ timeout_handlers_check(loop->context);
+ }
+
+ g_free(ufds);
+}
+
+void g_main_loop_quit(GMainLoop *loop)
+{
+ loop->is_running = FALSE;
+}
+
+void g_main_loop_unref(GMainLoop *loop)
+{
+ if (!loop->context)
+ return;
+
+ g_slist_foreach(loop->context->io_watches, (GFunc)watch_free, NULL);
+ g_slist_free(loop->context->io_watches);
+
+ g_slist_foreach(loop->context->timeouts, (GFunc)g_free, NULL);
+ g_slist_free(loop->context->timeouts);
+
+ g_free(loop->context);
+ loop->context = NULL;
+}
+
+guint g_timeout_add(guint interval, GSourceFunc function, gpointer data)
+{
+ GMainContext *context = g_main_context_default();
+ struct timeval tv;
+ guint secs;
+ guint msecs;
+ struct timeout *t;
+
+ t = g_new0(struct timeout, 1);
+
+ t->interval = interval;
+ t->function = function;
+ t->data = data;
+
+ gettimeofday(&tv, NULL);
+
+ secs = interval /1000;
+ msecs = interval - secs * 1000;
+
+ t->expiration.tv_sec = tv.tv_sec + secs;
+ t->expiration.tv_usec = tv.tv_usec + msecs * 1000;
+
+ if (t->expiration.tv_usec >= 1000000) {
+ t->expiration.tv_usec -= 1000000;
+ t->expiration.tv_sec++;
+ }
+
+ /* attach the timeout the default context */
+ t->id = context->next_id++;
+
+ if (context->timeout_lock)
+ context->proc_timeouts = g_slist_prepend(context->proc_timeouts, t);
+ else
+ context->timeouts = g_slist_prepend(context->timeouts, t);
+
+ return t->id;
+}
+
+guint g_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data)
+{
+ return g_timeout_add(interval, function, data);
+}
+
+guint g_idle_add(GSourceFunc function, gpointer data)
+{
+ return g_timeout_add(1, function, data);
+}
+
+/* GError */
+
+GError* g_error_new_literal(GQuark domain, gint code, const gchar *message)
+{
+ GError *err;
+
+ err = g_new(GError, 1);
+
+ err->domain = domain;
+ err->code = code;
+ err->message = g_strdup(message);
+
+ return err;
+}
+
+void g_set_error(GError **err, GQuark domain, gint code,
+ const gchar *format, ...)
+{
+ gchar msg[1024];
+ va_list ap;
+
+ if (!err)
+ return;
+
+ va_start(ap, format);
+
+ vsnprintf(msg, sizeof(msg) - 1, format, ap);
+
+ va_end(ap);
+
+ *err = g_error_new_literal(domain, code, msg);
+}
+
+void g_error_free(GError *err)
+{
+ g_free(err->message);
+ g_free(err);
+}
+
+/* Spawning related functions */
+
+static int child_watch_pipe[2] = { -1, -1 };
+
+static void sigchld_handler(int signal)
+{
+ int ret;
+ ret = write(child_watch_pipe[1], "B", 1);
+}
+
+static gboolean child_watch_remove(GMainContext *context, guint id)
+{
+ GSList *l;
+ struct child_watch *w;
+
+ for (l = context->child_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->child_watches =
+ g_slist_remove(context->child_watches, w);
+ g_free(w);
+
+ return TRUE;
+ }
+
+ for (l = context->proc_child_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->proc_child_watches =
+ g_slist_remove(context->proc_child_watches, w);
+ g_free(w);
+
+ return TRUE;
+ }
+
+
+ return FALSE;
+}
+
+static gboolean child_watch(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+ int ret;
+ char b[20];
+ GMainContext *context = g_main_context_default();
+
+ ret = read(child_watch_pipe[0], b, 20);
+
+ context->child_lock = TRUE;
+
+ while (context->child_watches) {
+ gint status;
+ struct child_watch *w = context->child_watches->data;
+
+ if (waitpid(w->pid, &status, WNOHANG) <= 0) {
+ context->child_watches =
+ g_slist_remove(context->child_watches, w);
+ context->proc_child_watches =
+ watch_list_add(context->proc_child_watches, w);
+ continue;
+ }
+
+ w->function(w->pid, status, w->user_data);
+
+ /* Check if the callback already removed us */
+ if (!g_slist_find(context->child_watches, w))
+ continue;
+
+ context->child_watches = g_slist_remove(context->child_watches, w);
+ g_free(w);
+ }
+
+ context->child_watches = context->proc_child_watches;
+ context->proc_child_watches = NULL;
+ context->child_lock = FALSE;
+
+ return TRUE;
+}
+
+static void init_child_pipe(void)
+{
+ struct sigaction action;
+ GIOChannel *io;
+
+ if (pipe(child_watch_pipe) < 0) {
+ fprintf(stderr, "Unable to initialize child watch pipe: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+
+ fcntl(child_watch_pipe[1], F_SETFL,
+ O_NONBLOCK | fcntl(child_watch_pipe[1], F_GETFL));
+
+ action.sa_handler = sigchld_handler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &action, NULL);
+
+ io = g_io_channel_unix_new(child_watch_pipe[0]);
+ g_io_add_watch(io, G_IO_IN, child_watch, NULL);
+ g_io_channel_unref(io);
+}
+
+static void exec_child(const gchar *working_directory,
+ gchar **argv, gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data)
+{
+ int null;
+
+ if (working_directory && chdir(working_directory) < 0)
+ _exit(EXIT_FAILURE);
+
+ if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) {
+ int open_max, fd, ret;
+
+ ret = 0;
+ open_max = sysconf(_SC_OPEN_MAX);
+ for (fd = 3; fd < open_max && ret == 0; fd++)
+ ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
+ }
+
+ null = open("/dev/null", O_RDWR);
+ if (!(flags & G_SPAWN_CHILD_INHERITS_STDIN))
+ dup2(null, STDIN_FILENO);
+ if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
+ dup2(null, STDOUT_FILENO);
+ if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
+ dup2(null, STDERR_FILENO);
+ if (null > 2)
+ close(null);
+
+ if (child_setup)
+ child_setup(user_data);
+
+ if (envp)
+ execve(argv[0], argv, envp);
+ else
+ execv(argv[0], argv);
+
+ /* exec failed if we get here */
+ _exit(EXIT_FAILURE);
+}
+
+gboolean g_spawn_async(const gchar *working_directory,
+ gchar **argv, gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ GError **error)
+{
+ GPid pid;
+
+ if (access(argv[0], X_OK) < 0) {
+ g_set_error(error, 0, 0, "%s is not executable", argv[0]);
+ return FALSE;
+ }
+
+ if (child_watch_pipe[0] < 0)
+ init_child_pipe();
+
+ /* Flush output streams so child doesn't get them */
+ fflush(NULL);
+
+ switch (pid = fork()) {
+ case -1:
+ g_set_error(error, 0, 0, "fork failed: %s", strerror(errno));
+ return FALSE;
+ case 0:
+ exec_child(working_directory, argv, envp, flags,
+ child_setup, user_data);
+ break;
+ default:
+ if (child_pid)
+ *child_pid = pid;
+ return TRUE;
+ }
+
+ /* Never reached */
+ return FALSE;
+}
+
+void g_spawn_close_pid(GPid pid)
+{
+ return;
+}
+
+guint g_child_watch_add(GPid pid, GChildWatchFunc func, gpointer user_data)
+{
+ struct child_watch *w;
+ GMainContext *context = g_main_context_default();
+
+ if (child_watch_pipe[0] < 0)
+ init_child_pipe();
+
+ w = g_new(struct child_watch, 1);
+
+ w->id = context->next_id++;
+ w->pid = pid;
+ w->function = func;
+ w->user_data = user_data;
+
+ if (context->child_lock)
+ context->proc_child_watches =
+ watch_list_add(context->proc_child_watches, w);
+ else
+ context->child_watches =
+ watch_list_add(context->child_watches, w);
+
+ return w->id;
+}
+
+gboolean g_source_remove(guint tag)
+{
+ GMainContext *context = g_main_context_default();
+
+ if (g_io_remove_watch(context, tag))
+ return TRUE;
+
+ if (g_timeout_remove(context, tag))
+ return TRUE;
+
+ if (child_watch_remove(context, tag))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* UTF-8 Validation: approximate copy/paste from glib2. */
+
+#define UNICODE_VALID(c) \
+ ((c) < 0x110000 && \
+ (((c) & 0xFFFFF800) != 0xD800) && \
+ ((c) < 0xFDD0 || (c) > 0xFDEF) && \
+ ((c) & 0xFFFE) != 0xFFFE)
+
+#define CONTINUATION_CHAR(c, val) \
+ do { \
+ if (((c) & 0xc0) != 0x80) /* 10xxxxxx */ \
+ goto failed; \
+ (val) <<= 6; \
+ (val) |= (c) & 0x3f; \
+ } while (0)
+
+#define INCREMENT_AND_CHECK_MAX(p, i, max_len) \
+ do { \
+ (i)++; \
+ if ((p)[(i)] == '\0' || ((max_len) >= 0 && (i) >= (max_len))) \
+ goto failed; \
+ } while (0)
+
+
+gboolean g_utf8_validate(const gchar *str, gssize max_len, const gchar **end)
+{
+ unsigned long val, min, i;
+ const unsigned char *p, *last;
+
+ min = val = 0;
+
+ for (p = (unsigned char *) str, i = 0; p[i]; i++) {
+ if (max_len >= 0 && i >= max_len)
+ break;
+
+ if (p[i] < 128)
+ continue;
+
+ last = &p[i];
+
+ if ((p[i] & 0xe0) == 0xc0) { /* 110xxxxx */
+ if ((p[i] & 0x1e) == 0)
+ goto failed;
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ if ((p[i] & 0xc0) != 0x80)
+ goto failed; /* 10xxxxxx */
+ } else {
+ if ((p[i] & 0xf0) == 0xe0) {
+ /* 1110xxxx */
+ min = (1 << 11);
+ val = p[i] & 0x0f;
+ goto two_remaining;
+ } else if ((p[i] & 0xf8) == 0xf0) {
+ /* 11110xxx */
+ min = (1 << 16);
+ val = p[i] & 0x07;
+ } else
+ goto failed;
+
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ CONTINUATION_CHAR(p[i], val);
+two_remaining:
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ CONTINUATION_CHAR(p[i], val);
+
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ CONTINUATION_CHAR(p[i], val);
+
+ if (val < min || !UNICODE_VALID(val))
+ goto failed;
+ }
+ }
+
+ if (end)
+ *end = (const gchar *) &p[i];
+
+ return TRUE;
+
+failed:
+ if (end)
+ *end = (const gchar *) last;
+
+ return FALSE;
+}
+
+/* GSList functions */
+
+GSList *g_slist_append(GSList *list, void *data)
+{
+ GSList *entry, *tail;
+
+ entry = g_new(GSList, 1);
+
+ entry->data = data;
+ entry->next = NULL;
+
+ if (!list)
+ return entry;
+
+ /* Find the end of the list */
+ for (tail = list; tail->next; tail = tail->next);
+
+ tail->next = entry;
+
+ return list;
+}
+
+GSList *g_slist_prepend(GSList *list, void *data)
+{
+ GSList *entry;
+
+ entry = g_new(GSList, 1);
+
+ entry->data = data;
+ entry->next = list;
+
+ return entry;
+}
+
+GSList *g_slist_insert_sorted(GSList *list, void *data, GCompareFunc cmp_func)
+{
+ GSList *tmp, *prev, *entry;
+ int cmp;
+
+ entry = g_new(GSList, 1);
+
+ entry->data = data;
+ entry->next = NULL;
+
+ if (!list)
+ return entry;
+
+ prev = NULL;
+ tmp = list;
+
+ cmp = cmp_func(data, tmp->data);
+
+ while (tmp->next && cmp > 0) {
+ prev = tmp;
+ tmp = tmp->next;
+
+ cmp = cmp_func(data, tmp->data);
+ }
+
+ if (!tmp->next && cmp > 0) {
+ tmp->next = entry;
+ return list;
+ }
+
+ if (prev) {
+ prev->next = entry;
+ entry->next = tmp;
+ return list;
+ } else {
+ entry->next = list;
+ return entry;
+ }
+}
+
+GSList *g_slist_remove(GSList *list, void *data)
+{
+ GSList *l, *next, *prev = NULL, *match = NULL;
+
+ if (!list)
+ return NULL;
+
+ for (l = list; l != NULL; l = l->next) {
+ if (l->data == data) {
+ match = l;
+ break;
+ }
+ prev = l;
+ }
+
+ if (!match)
+ return list;
+
+ next = match->next;
+
+ g_free(match);
+
+ /* If the head was removed, return the next element */
+ if (!prev)
+ return next;
+
+ prev->next = next;
+
+ return list;
+}
+
+GSList *g_slist_find(GSList *list, gconstpointer data)
+{
+ GSList *l;
+
+ for (l = list; l != NULL; l = l->next) {
+ if (l->data == data)
+ return l;
+ }
+
+ return NULL;
+}
+
+GSList *g_slist_find_custom(GSList *list, const void *data,
+ GCompareFunc cmp_func)
+{
+ GSList *l;
+
+ for (l = list; l != NULL; l = l->next) {
+ if (!cmp_func(l->data, data))
+ return l;
+ }
+
+ return NULL;
+}
+
+static GSList *g_slist_sort_merge(GSList *l1, GSList *l2,
+ GCompareFunc cmp_func)
+{
+ GSList list, *l;
+ int cmp;
+
+ l = &list;
+
+ while (l1 && l2) {
+ cmp = cmp_func(l1->data, l2->data);
+
+ if (cmp <= 0) {
+ l = l->next = l1;
+ l1 = l1->next;
+ } else {
+ l = l->next = l2;
+ l2 = l2->next;
+ }
+ }
+
+ l->next = l1 ? l1 : l2;
+
+ return list.next;
+}
+
+GSList *g_slist_sort(GSList *list, GCompareFunc cmp_func)
+{
+ GSList *l1, *l2;
+
+ if (!list || !list->next)
+ return list;
+
+ l1 = list;
+ l2 = list->next;
+
+ while ((l2 = l2->next) != NULL) {
+ if ((l2 = l2->next) == NULL)
+ break;
+ l1 = l1->next;
+ }
+
+ l2 = l1->next;
+ l1->next = NULL;
+
+ return g_slist_sort_merge(g_slist_sort(list, cmp_func),
+ g_slist_sort(l2, cmp_func), cmp_func);
+}
+
+int g_slist_length(GSList *list)
+{
+ int len;
+
+ for (len = 0; list != NULL; list = list->next)
+ len++;
+
+ return len;
+}
+
+void g_slist_foreach(GSList *list, GFunc func, void *user_data)
+{
+ while (list) {
+ GSList *next = list->next;
+ func(list->data, user_data);
+ list = next;
+ }
+}
+
+void g_slist_free(GSList *list)
+{
+ GSList *l, *next;
+
+ for (l = list; l != NULL; l = next) {
+ next = l->next;
+ g_free(l);
+ }
+}
+
+GSList *g_slist_nth(GSList *list, guint n)
+{
+ while (n-- > 0 && list)
+ list = list->next;
+
+ return list;
+}
+
+gpointer g_slist_nth_data(GSList *list, guint n)
+{
+ while (n-- > 0 && list)
+ list = list->next;
+
+ return list ? list->data : NULL;
+}
+
+gint g_slist_position(GSList *list, GSList *link)
+{
+ gint i;
+
+ for (i = 0; list; list = list->next, i++) {
+ if (list == link)
+ return i;
+ }
+
+ return -1;
+}
+
+GSList* g_slist_last(GSList *list)
+{
+ if (list)
+ while (list->next)
+ list = list->next;
+
+ return list;
+}
+
+static inline GSList* _g_slist_remove_link(GSList *list, GSList *link)
+{
+ GSList *tmp;
+ GSList *prev;
+
+ prev = NULL;
+ tmp = list;
+
+ while (tmp) {
+ if (tmp == link) {
+ if (prev)
+ prev->next = tmp->next;
+ if (list == tmp)
+ list = list->next;
+
+ tmp->next = NULL;
+ break;
+ }
+
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ return list;
+}
+
+GSList* g_slist_delete_link(GSList *list, GSList *link)
+{
+ list = _g_slist_remove_link(list, link);
+ g_free(link);
+
+ return list;
+}
+
+/* Memory allocation functions */
+
+gpointer g_malloc(gulong n_bytes)
+{
+ gpointer mem;
+
+ if (!n_bytes)
+ return NULL;
+
+ mem = malloc((size_t) n_bytes);
+ if (!mem) {
+ fprintf(stderr, "g_malloc: failed to allocate %lu bytes",
+ n_bytes);
+ abort();
+ }
+
+ return mem;
+}
+
+gpointer g_malloc0(gulong n_bytes)
+{
+ gpointer mem;
+
+ if (!n_bytes)
+ return NULL;
+
+ mem = g_malloc(n_bytes);
+
+ memset(mem, 0, (size_t) n_bytes);
+
+ return mem;
+}
+
+gpointer g_try_malloc(gulong n_bytes)
+{
+ if (!n_bytes)
+ return NULL;
+
+ return malloc((size_t) n_bytes);
+}
+
+gpointer g_try_malloc0(gulong n_bytes)
+{
+ gpointer mem;
+
+ mem = g_try_malloc(n_bytes);
+ if (mem)
+ memset(mem, 0, (size_t) n_bytes);
+
+ return mem;
+}
+
+gpointer g_realloc(gpointer mem, gulong n_bytes)
+{
+ mem = realloc(mem, n_bytes);
+ if (!mem) {
+ fprintf(stderr, "g_realloc: failed to allocate %lu bytes",
+ n_bytes);
+ abort();
+ }
+
+ return mem;
+}
+
+void g_free(gpointer mem)
+{
+ if (mem)
+ free(mem);
+}
+
+gchar *g_strdup(const gchar *str)
+{
+ gchar *s;
+
+ if (!str)
+ return NULL;
+
+ s = strdup(str);
+ if (!s) {
+ fprintf(stderr, "strdup: failed to allocate new string");
+ abort();
+ }
+
+ return s;
+}
+
+gchar *g_strdup_printf(const gchar *format, ...)
+{
+ va_list args;
+ gchar buffer[1024];
+ gint length;
+
+ va_start(args, format);
+ length = vsnprintf(buffer, sizeof(buffer) - 1, format, args);
+ va_end(args);
+
+ return g_strdup(buffer);
+}
+
+gchar *g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delim)
+{
+ register gchar *c;
+
+ if (!string)
+ return NULL;
+
+ for (c = string; *c; c++)
+ if (strchr(delimiters, *c))
+ *c = new_delim;
+
+ return string;
+}
+
+gchar *g_strconcat(const gchar *string1, ...)
+{
+ gsize l;
+ va_list args;
+ gchar *s, *concat;
+
+ if (!string1)
+ return NULL;
+
+ l = 1 + strlen(string1);
+ va_start(args, string1);
+ s = va_arg(args, gchar *);
+ while (s) {
+ l += strlen(s);
+ s = va_arg(args, gchar *);
+ }
+ va_end (args);
+
+ concat = g_new(gchar, l);
+ concat[0] = '\0';
+
+ va_start(args, string1);
+ s = va_arg(args, gchar*);
+ while (s) {
+ strcat(concat, s);
+ s = va_arg(args, gchar *);
+ }
+ va_end (args);
+
+ return concat;
+}
+
+gsize g_strlcat(gchar *dest, const gchar *src, gsize dest_size)
+{
+ gchar *d = dest;
+ const gchar *s = src;
+ gsize bytes_left = dest_size;
+ gsize dlength; /* Logically, MIN(strlen(d), dest_size) */
+
+ if (!d || !s)
+ return 0;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (*d != 0 && bytes_left-- != 0)
+ d++;
+ dlength = d - dest;
+ bytes_left = dest_size - dlength;
+
+ if (bytes_left == 0)
+ return dlength + strlen(s);
+
+ while (*s != 0) {
+ if (bytes_left != 1) {
+ *d++ = *s;
+ bytes_left--;
+ }
+ s++;
+ }
+ *d = 0;
+
+ return dlength + (s - src); /* count does not include NULL */
+}
+
+gchar **g_strsplit(const gchar *string, const gchar *delimiter, gint max_tokens)
+{
+ GSList *string_list = NULL, *slist;
+ gchar **str_array, *s;
+ guint n = 0;
+ const gchar *remainder;
+
+ if (string == NULL || delimiter == NULL || delimiter[0] == '\0')
+ return NULL;
+
+ if (max_tokens < 1)
+ max_tokens = INT_MAX;
+
+ remainder = string;
+ s = strstr(remainder, delimiter);
+ if (s) {
+ gsize delimiter_len = strlen(delimiter);
+
+ while (--max_tokens && s) {
+ gsize len;
+ gchar *tmp;
+
+ len = s - remainder;
+ tmp = g_new(char, len);
+ memcpy(tmp, remainder, len);
+ string_list = g_slist_prepend(string_list, tmp);
+ n++;
+ remainder = s + delimiter_len;
+ s = strstr(remainder, delimiter);
+ }
+ }
+ if (*string) {
+ n++;
+ string_list = g_slist_prepend(string_list, g_strdup(remainder));
+ }
+
+ str_array = g_new(gchar *, n + 1);
+
+ str_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ str_array[n--] = slist->data;
+
+ g_slist_free(string_list);
+
+ return str_array;
+}
+
+gchar *g_ascii_strup(const gchar *str, gssize len)
+{
+ int i;
+ gchar *s;
+
+ s = g_strdup(str);
+ if (!s)
+ return NULL;
+
+ if (len < 0)
+ len = strlen(s);
+
+ for (i = 0; i < len; i++)
+ s[i] = toupper(s[i]);
+
+ return s;
+}
+
+gboolean g_str_equal(gconstpointer v1, gconstpointer v2)
+{
+ const gchar *string1 = v1;
+ const gchar *string2 = v2;
+
+ return strcmp(string1, string2) == 0;
+}
+
+gboolean g_str_has_prefix(const gchar *str, const gchar *prefix)
+{
+ int str_len;
+ int prefix_len;
+
+ if (str == NULL || prefix == NULL)
+ return FALSE;
+
+ str_len = strlen (str);
+ prefix_len = strlen (prefix);
+
+ if (str_len < prefix_len)
+ return FALSE;
+
+ return strncmp(str, prefix, prefix_len) == 0;
+}
+
+gboolean g_str_has_suffix(const gchar *str, const gchar *suffix)
+{
+ int str_len;
+ int suffix_len;
+
+ if (!str || !suffix)
+ return FALSE;
+
+ str_len = strlen(str);
+ suffix_len = strlen(suffix);
+
+ if (str_len < suffix_len)
+ return FALSE;
+
+ return strcmp(str + str_len - suffix_len, suffix) == 0;
+}
+
+void g_strfreev(gchar **str_array)
+{
+ int i;
+
+ if (str_array == NULL)
+ return;
+
+ for(i = 0; str_array[i] != NULL; i++)
+ g_free(str_array[i]);
+
+ g_free(str_array);
+}
+
+/* GKeyFile */
+
+struct _GKeyFile {
+ gchar *filename;
+};
+
+GKeyFile *g_key_file_new(void)
+{
+ return g_new0(GKeyFile, 1);
+}
+
+void g_key_file_free(GKeyFile *key_file)
+{
+ g_free(key_file->filename);
+ g_free(key_file);
+}
+
+gboolean g_key_file_load_from_file(GKeyFile *key_file,
+ const gchar *file,
+ GKeyFileFlags flags,
+ GError **error)
+{
+ key_file->filename = g_strdup(file);
+ return TRUE;
+}
+
+static char *next_line(const char *ptr)
+{
+ char *nl;
+
+ nl = strchr(ptr, '\n');
+ if (!nl)
+ return NULL;
+
+ if (nl[1] == '\0')
+ return NULL;
+
+ return nl + 1;
+}
+
+gchar *g_key_file_get_string(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error)
+{
+ struct stat st;
+ char *map, *line, *group = NULL, *value = NULL;
+ off_t size;
+ size_t key_len, group_len;
+ int fd, err = 0;
+
+ fd = open(key_file->filename, O_RDONLY);
+ if (fd < 0) {
+ g_set_error(error, 0, 0, "%s: %s", key_file->filename,
+ strerror(errno));
+ return NULL;
+ }
+
+ if (flock(fd, LOCK_SH) < 0) {
+ err = errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = errno;
+ goto unlock;
+ }
+
+ group_len = strlen(group_name);
+ key_len = strlen(key);
+
+ for (line = map; line != NULL; line = next_line(line)) {
+ int i;
+ size_t to_copy, value_len;
+ char tmp[1024], *nl;
+
+ if (*line == '#')
+ continue;
+
+ if (!group) {
+ if (line[0] != '[' || strncmp(line + 1, group_name, group_len))
+ continue;
+ if (line[group_len + 1] == ']')
+ group = line + 1;
+ continue;
+ }
+
+ if (strncmp(line, key, key_len))
+ continue;
+
+ for (i = key_len; line[i] != '\n'; i++) {
+ if (line[i] == '=')
+ break;
+ if (!isspace(line[i]))
+ break;
+ }
+
+ if (line[i] != '=')
+ continue;
+
+ nl = strchr(line, '\n');
+ if (!nl)
+ continue;
+
+ value_len = nl - (line + i + 1);
+ to_copy = value_len > (sizeof(tmp) - 1) ? sizeof(tmp) - 1 : value_len;
+ memset(tmp, 0, sizeof(tmp));
+ strncpy(tmp, line + i + 1, to_copy);
+
+ value = g_strdup(tmp);
+ break;
+ }
+
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+
+ if (err)
+ g_set_error(error, 0, 0, "%s: %s", key_file->filename,
+ strerror(err));
+ else if (!group)
+ g_set_error(error, 0, 0, "%s: group %s not found",
+ key_file->filename, group_name);
+ else if (!value)
+ g_set_error(error, 0, 0, "%s: key %s not found",
+ key_file->filename, key);
+
+ return value;
+}
+
+gboolean g_key_file_get_boolean(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = g_key_file_get_string(key_file, group_name, key, error);
+ if (!str)
+ return FALSE;
+
+ if (strcmp(str, "true") == 0 || strcmp(str, "1") == 0)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ g_free(str);
+
+ return ret;
+}
+
+gint g_key_file_get_integer(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error)
+{
+ int ret;
+ gchar *str;
+
+ str = g_key_file_get_string(key_file, group_name, key, error);
+ if (!str)
+ return 0;
+
+ ret = atoi(str);
+
+ g_free(str);
+
+ return ret;
+}
+
+gchar **g_key_file_get_string_list(GKeyFile *key_file, const gchar *group_name,
+ const gchar *key, gsize *length,
+ GError **error)
+{
+ gchar *str, *item, **list;
+ int items = 0;
+
+ str = g_key_file_get_string(key_file, group_name, key, error);
+ if (!str)
+ return NULL;
+
+ items = 0;
+ list = g_new0(char *, 1);
+
+ item = strtok(str, ",");
+ while (item) {
+ items++;
+
+ list = g_renew(char *, list, items + 1);
+
+ list[items - 1] = g_strdup(item);
+ list[items] = NULL;
+
+ item = strtok(NULL, ",");
+ }
+
+ g_free(str);
+
+ return list;
+}
+
+/* GString */
+
+#define MY_MAXSIZE ((gsize)-1)
+
+static gsize nearest_power(gsize base, gsize num)
+{
+ gsize n = base;
+
+ if (num > MY_MAXSIZE / 2)
+ return MY_MAXSIZE;
+
+ while (n < num)
+ n <<= 1;
+
+ return n;
+}
+
+static void g_string_maybe_expand(GString *string, gsize len)
+{
+ if (string->len + len < string->allocated_len)
+ return;
+
+ string->allocated_len = nearest_power(1, string->len + len + 1);
+ string->str = g_realloc(string->str, string->allocated_len);
+}
+
+static GString *g_string_sized_new(gsize dfl_size)
+{
+ GString *string;
+
+ string = g_new0(GString, 1);
+
+ g_string_maybe_expand(string, dfl_size);
+ string->str[0] = '\0';
+
+ return string;
+}
+
+static GString *g_string_append_len(GString *string, const gchar *val, gssize len)
+{
+ g_string_maybe_expand(string, len);
+
+ if (len == 1)
+ string->str[string->len] = *val;
+ else
+ memcpy(string->str + string->len, val, len);
+
+ string->len += len;
+ string->str[string->len] = '\0';
+
+ return string;
+}
+
+GString *g_string_new(const gchar *init)
+{
+ GString *string;
+ gint len;
+
+ if (init == NULL || *init == '\0')
+ return g_string_sized_new(2);
+
+ len = strlen(init);
+ string = g_string_sized_new(len + 2);
+
+ g_string_append_len(string, init, len);
+
+ return string;
+}
+
+void g_string_append_printf(GString *string, const gchar *format, ...)
+{
+ gchar buffer[1024];
+ gint length;
+ va_list args;
+
+ va_start(args, format);
+ length = vsnprintf(buffer, sizeof(buffer) - 1, format, args);
+ va_end(args);
+
+ g_string_append_len(string, buffer, length);
+}
+
+gchar *g_string_free(GString *string, gboolean free_segment)
+{
+ gchar *segment;
+
+ if (free_segment) {
+ g_free(string->str);
+ segment = NULL;
+ } else
+ segment = string->str;
+
+ g_free(string);
+
+ return segment;
+}
+
+/* GMarkup */
+
+struct _GMarkupParseContext {
+ char dummy;
+};
+
+GMarkupParseContext *g_markup_parse_context_new(const GMarkupParser *parser,
+ GMarkupParseFlags flags,
+ gpointer user_data,
+ GDestroyNotify user_data_dnotify)
+{
+ return g_new0(GMarkupParseContext, 1);
+}
+
+gboolean g_markup_parse_context_parse(GMarkupParseContext *context,
+ const gchar *text, gssize text_len,
+ GError **error)
+{
+ g_set_error(error, 0, 0, "Not implemented");
+ return FALSE;
+}
+
+void g_markup_parse_context_free(GMarkupParseContext *context)
+{
+ g_free(context);
+}
+
+static gchar *g_build_pathname_va(const gchar *first_element,
+ va_list args, gpointer *data)
+{
+ gchar result[PATH_MAX], *element;
+
+ strncpy(result, first_element, PATH_MAX);
+ element = va_arg(args, gchar *);
+
+ while (element) {
+ g_strlcat(result, "/", PATH_MAX);
+ g_strlcat(result, element, PATH_MAX);
+ element = va_arg(args, gchar *);
+ }
+
+ va_end(args);
+
+ return g_strdup(result);
+}
+
+gchar *g_build_filename(const gchar *first_element, ...)
+{
+ gchar *str;
+ va_list args;
+
+ va_start(args, first_element);
+ str = g_build_pathname_va(first_element, args, NULL);
+ va_end(args);
+
+ return str;
+}
+
+/* GDir */
+
+GDir *g_dir_open(const gchar *path, guint flags, GError **error)
+{
+ GDir *dir;
+
+ if (path == NULL)
+ return NULL;
+
+ dir = g_new(GDir, 1);
+
+ dir->dirp = opendir(path);
+
+ if (dir->dirp)
+ return dir;
+
+ /* error case */
+ g_set_error(error, 0, 0, "Error opening directory '%s': %s",
+ path, strerror(errno));
+
+ g_free(dir);
+
+ return NULL;
+}
+
+const gchar *g_dir_read_name(GDir *dir)
+{
+ struct dirent *entry;
+
+ if (dir == NULL)
+ return NULL;
+
+ entry = readdir(dir->dirp);
+
+ while (entry && (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0))
+ entry = readdir(dir->dirp);
+
+ return entry ? entry->d_name : NULL;
+}
+
+void g_dir_close(GDir *dir)
+{
+ if (dir == NULL)
+ return;
+
+ closedir(dir->dirp);
+ g_free(dir);
+}
diff --git a/utils/eglib/gmain.h b/utils/eglib/gmain.h
new file mode 100644
index 00000000..fa218da4
--- /dev/null
+++ b/utils/eglib/gmain.h
@@ -0,0 +1,404 @@
+#ifndef __GMAIN_H
+#define __GMAIN_H
+
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+typedef char gchar;
+typedef short gshort;
+typedef long glong;
+typedef int gint;
+typedef gint gboolean;
+
+typedef unsigned char guchar;
+typedef unsigned short gushort;
+typedef unsigned long gulong;
+typedef unsigned int guint;
+
+typedef uint8_t guint8;
+typedef uint16_t guint16;
+typedef uint32_t guint32;
+
+typedef float gfloat;
+typedef double gdouble;
+
+typedef void * gpointer;
+typedef const void * gconstpointer;
+
+typedef size_t gsize;
+typedef ssize_t gssize;
+
+#define GPOINTER_TO_INT(p) ((gint) (glong) (p))
+#define GPOINTER_TO_UINT(p) ((guint) (gulong) (p))
+
+#define GINT_TO_POINTER(i) ((gpointer) (glong) (i))
+#define GUINT_TO_POINTER(u) ((gpointer) (gulong) (u))
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX INT_MAX
+#endif
+
+#define g_ntohs(val) ntohs(val)
+#define g_ntohl(val) ntohl(val)
+#define g_htons(val) htons(val)
+#define g_htonl(val) htonl(val)
+
+typedef pid_t GPid;
+
+#define MIN_TIMEOUT(a, b) (((a) < (b)) ? (a) : (b))
+
+typedef struct _GIOChannel GIOChannel;
+
+typedef gboolean (*GSourceFunc) (gpointer data);
+
+typedef struct _GMainContext GMainContext;
+
+typedef struct _GMainLoop GMainLoop;
+
+typedef enum {
+ G_IO_ERROR_NONE,
+ G_IO_ERROR_AGAIN,
+ G_IO_ERROR_INVAL,
+ G_IO_ERROR_UNKNOWN
+} GIOError;
+
+typedef enum {
+ G_IO_STATUS_ERROR = -1,
+ G_IO_STATUS_NORMAL = 0,
+ G_IO_STATUS_EOF = 1,
+ G_IO_STATUS_AGAIN = 2
+} GIOStatus;
+
+typedef enum {
+ G_IO_FLAG_APPEND = 1 << 0,
+ G_IO_FLAG_NONBLOCK = 1 << 1,
+ G_IO_FLAG_IS_READABLE = 1 << 2,
+ G_IO_FLAG_IS_WRITEABLE = 1 << 3,
+ G_IO_FLAG_IS_SEEKABLE = 1 << 4,
+ G_IO_FLAG_MASK = (1 << 5) - 1,
+ G_IO_FLAG_GET_MASK = G_IO_FLAG_MASK,
+ G_IO_FLAG_SET_MASK = G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK
+} GIOFlags;
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#undef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#undef ABS
+#define ABS(a) (((a) < 0) ? -(a) : (a))
+
+#undef CLAMP
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+
+/* GError */
+
+typedef guint32 GQuark;
+
+typedef struct {
+ GQuark domain;
+ gint code;
+ gchar *message;
+} GError;
+
+void g_set_error(GError **err, GQuark domain, gint code,
+ const gchar *format, ...);
+GError* g_error_new_literal(GQuark domain, gint code, const gchar *message);
+void g_error_free(GError *err);
+
+typedef enum {
+ G_IO_IN = POLLIN,
+ G_IO_OUT = POLLOUT,
+ G_IO_PRI = POLLPRI,
+ G_IO_ERR = POLLERR,
+ G_IO_HUP = POLLHUP,
+ G_IO_NVAL = POLLNVAL
+} GIOCondition;
+
+#define G_PRIORITY_HIGH -100
+#define G_PRIORITY_DEFAULT 0
+#define G_PRIORITY_HIGH_IDLE 100
+#define G_PRIORITY_DEFAULT_IDLE 200
+#define G_PRIORITY_LOW 300
+
+typedef void (*GDestroyNotify) (gpointer data);
+typedef gboolean (*GIOFunc) (GIOChannel *source, GIOCondition condition,
+ gpointer data);
+
+GIOError g_io_channel_read(GIOChannel *channel, gchar *buf, gsize count,
+ gsize *bytes_read);
+GIOError g_io_channel_write(GIOChannel *channel, const gchar *buf, gsize count,
+ gsize *bytes_written);
+
+void g_io_channel_close(GIOChannel *channel);
+
+GIOChannel *g_io_channel_unix_new(int fd);
+GIOChannel *g_io_channel_ref(GIOChannel *channel);
+void g_io_channel_unref(GIOChannel *channel);
+void g_io_channel_set_close_on_unref(GIOChannel *channel, gboolean do_close);
+gint g_io_channel_unix_get_fd(GIOChannel *channel);
+GIOStatus g_io_channel_set_flags(GIOChannel *channel, GIOFlags flags,
+ GError **error);
+guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,
+ GIOFunc func, gpointer user_data);
+guint g_io_add_watch_full(GIOChannel *channel, gint priority,
+ GIOCondition condition, GIOFunc func,
+ gpointer user_data, GDestroyNotify notify);
+
+GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running);
+void g_main_loop_run(GMainLoop *loop);
+void g_main_loop_quit(GMainLoop *loop);
+void g_main_loop_unref(GMainLoop *loop);
+guint g_timeout_add(guint interval, GSourceFunc function, gpointer data);
+guint g_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data);
+guint g_idle_add(GSourceFunc function, gpointer data);
+gboolean g_source_remove(guint tag);
+
+/* Spawning related functions */
+
+typedef enum {
+ G_SPAWN_LEAVE_DESCRIPTORS_OPEN = 1 << 0,
+ G_SPAWN_DO_NOT_REAP_CHILD = 1 << 1,
+ /* look for argv[0] in the path i.e. use execvp() */
+ G_SPAWN_SEARCH_PATH = 1 << 2,
+ /* Dump output to /dev/null */
+ G_SPAWN_STDOUT_TO_DEV_NULL = 1 << 3,
+ G_SPAWN_STDERR_TO_DEV_NULL = 1 << 4,
+ G_SPAWN_CHILD_INHERITS_STDIN = 1 << 5,
+ G_SPAWN_FILE_AND_ARGV_ZERO = 1 << 6
+} GSpawnFlags;
+
+typedef void (*GSpawnChildSetupFunc) (gpointer user_data);
+
+gboolean g_spawn_async(const gchar *working_directory,
+ gchar **argv, gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ GError **error);
+
+void g_spawn_close_pid(GPid pid);
+
+typedef void (*GChildWatchFunc) (GPid pid, gint status, gpointer data);
+
+guint g_child_watch_add(GPid pid, GChildWatchFunc func, gpointer user_data);
+
+gboolean g_utf8_validate(const gchar *str, gssize max_len, const gchar **end);
+
+#define g_main_new(is_running) g_main_loop_new(NULL, is_running);
+#define g_main_run(loop) g_main_loop_run(loop)
+#define g_main_quit(loop) g_main_loop_quit(loop)
+#define g_main_unref(loop) g_main_loop_unref(loop)
+
+/* GSList declarations */
+
+typedef struct _GSList {
+ void *data;
+ struct _GSList *next;
+} GSList;
+
+typedef int (*GCompareFunc)(const void *a, const void *b);
+typedef void (*GFunc)(void *data, void *user_data);
+
+GSList *g_slist_append(GSList *list, void *data);
+
+GSList *g_slist_prepend(GSList *list, void *data);
+
+GSList *g_slist_insert_sorted(GSList *list, void *data, GCompareFunc cmp_func);
+
+GSList *g_slist_remove(GSList *list, void *data);
+
+GSList *g_slist_find(GSList *list, gconstpointer data);
+
+GSList *g_slist_find_custom(GSList *list, const void *data,
+ GCompareFunc cmp_func);
+
+GSList *g_slist_sort(GSList *list, GCompareFunc cmp_func);
+
+int g_slist_length(GSList *list);
+
+void g_slist_foreach(GSList *list, GFunc func, void *user_data);
+void g_slist_free(GSList *list);
+GSList *g_slist_delete_link(GSList *list, GSList *link);
+
+GSList *g_slist_nth(GSList *list, guint n);
+gpointer g_slist_nth_data(GSList *list, guint n);
+int g_slist_position(GSList *list, GSList *link);
+GSList* g_slist_last(GSList *list);
+
+#define g_slist_next(l) ((l)->next)
+
+/* Memory allocation related */
+
+gpointer g_malloc(gulong n_bytes);
+gpointer g_malloc0(gulong n_bytes);
+gpointer g_try_malloc(gulong n_bytes);
+gpointer g_try_malloc0(gulong n_bytes);
+gpointer g_realloc(gpointer mem, gulong n_bytes);
+
+void g_free(gpointer mem);
+
+gchar *g_strdup(const gchar *str);
+gchar* g_strdup_printf(const gchar *format, ...);
+gchar* g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delim);
+gchar *g_strconcat(const gchar *string1, ...);
+gsize g_strlcat(gchar *dest, const gchar *src, gsize dest_size);
+gchar **g_strsplit(const gchar *string, const gchar *delimiter, gint max_tokens);
+gchar *g_ascii_strup(const gchar *str, gssize len);
+gboolean g_str_equal(gconstpointer v1, gconstpointer v2);
+gboolean g_str_has_prefix(const gchar *str, const gchar *prefix);
+gboolean g_str_has_suffix(const gchar *str, const gchar *suffix);
+void g_strfreev(gchar **str_array);
+
+#define g_new(struct_type, n_structs) \
+ ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_new0(struct_type, n_structs) \
+ ((struct_type *) g_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_new(struct_type, n_structs) \
+ ((struct_type *) g_try_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_new0(struct_type, n_structs) \
+ ((struct_type *) g_try_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_renew(struct_type, mem, n_structs) \
+ ((struct_type *) g_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+
+/* GKeyFile */
+
+typedef enum {
+ G_KEY_FILE_NONE = 0,
+ G_KEY_FILE_KEEP_COMMENTS = 1 << 0,
+ G_KEY_FILE_KEEP_TRANSLATIONS = 1 << 1
+} GKeyFileFlags;
+
+typedef struct _GKeyFile GKeyFile;
+
+GKeyFile *g_key_file_new(void);
+
+void g_key_file_free(GKeyFile *key_file);
+
+gboolean g_key_file_load_from_file(GKeyFile *key_file,
+ const gchar *file,
+ GKeyFileFlags flags,
+ GError **error);
+
+gchar *g_key_file_get_string(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+
+gboolean g_key_file_get_boolean(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+
+gint g_key_file_get_integer(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+
+gchar **g_key_file_get_string_list(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key, gsize *length,
+ GError **error);
+/* GString */
+
+typedef struct {
+ gchar *str;
+ gsize len;
+ gsize allocated_len;
+} GString;
+
+GString *g_string_new(const gchar *init);
+
+void g_string_append_printf(GString *string, const gchar *format, ...);
+
+gchar *g_string_free(GString *string, gboolean free_segment);
+
+/* GMarkup */
+
+typedef enum {
+ G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG = 1 << 0,
+ G_MARKUP_TREAT_CDATA_AS_TEXT = 1 << 1
+} GMarkupParseFlags;
+
+typedef struct _GMarkupParseContext GMarkupParseContext;
+typedef struct _GMarkupParser GMarkupParser;
+
+struct _GMarkupParser {
+ /* Called for open tags <foo bar="baz"> */
+ void (*start_element) (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for close tags </foo> */
+ void (*end_element) (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for character data */
+ /* text is not nul-terminated */
+ void (*text) (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for strings that should be re-saved verbatim in this same
+ * position, but are not otherwise interpretable. At the moment
+ * this includes comments and processing instructions.
+ */
+ /* text is not nul-terminated. */
+ void (*passthrough) (GMarkupParseContext *context,
+ const gchar *passthrough_text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+
+ /* Called on error, including one set by other
+ * methods in the vtable. The GError should not be freed.
+ */
+ void (*error) (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data);
+};
+
+GMarkupParseContext *g_markup_parse_context_new(const GMarkupParser *parser,
+ GMarkupParseFlags flags,
+ gpointer user_data,
+ GDestroyNotify user_data_dnotify);
+
+gboolean g_markup_parse_context_parse(GMarkupParseContext *context,
+ const gchar *text, gssize text_len,
+ GError **error);
+
+void g_markup_parse_context_free(GMarkupParseContext *context);
+
+/* GDir */
+
+typedef struct _GDir GDir;
+
+GDir *g_dir_open(const gchar *path, guint flags, GError **error);
+const gchar *g_dir_read_name(GDir *dir);
+void g_dir_close(GDir *dir);
+
+/* Various */
+
+gchar *g_build_filename(const gchar *first_element, ...);
+
+#endif /* __GMAIN_H */
diff --git a/utils/eglib/gmodule.c b/utils/eglib/gmodule.c
new file mode 100644
index 00000000..7224a9f6
--- /dev/null
+++ b/utils/eglib/gmodule.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <gmain.h>
+#include <gmodule.h>
+
+struct _GModule {
+ void *handle;
+ gchar *file_name;
+};
+
+static const char *dl_error_string = NULL;
+
+GModule *g_module_open(const gchar *file_name, GModuleFlags flags)
+{
+ GModule *module;
+
+ module = g_try_new0(GModule, 1);
+ if (module == NULL) {
+ dl_error_string = strerror(ENOMEM);
+ return NULL;
+ }
+
+ module->handle = dlopen(file_name, flags);
+
+ if (module->handle == NULL) {
+ dl_error_string = dlerror();
+ g_free(module);
+ return NULL;
+ }
+
+ module->file_name = g_strdup(file_name);
+
+ return module;
+}
+
+gboolean g_module_symbol(GModule *module, const gchar *symbol_name,
+ gpointer *symbol)
+{
+ void *sym;
+
+ dlerror();
+ sym = dlsym(module->handle, symbol_name);
+ dl_error_string = dlerror();
+
+ if (dl_error_string != NULL)
+ return FALSE;
+
+ *symbol = sym;
+
+ return TRUE;
+}
+
+gboolean g_module_close(GModule *module)
+{
+ if (dlclose(module->handle) != 0) {
+ dl_error_string = dlerror();
+ return FALSE;
+ }
+
+ g_free(module->file_name);
+ g_free(module);
+
+ return TRUE;
+}
+
+const gchar *g_module_error(void)
+{
+ const char *str;
+
+ str = dl_error_string;
+ dl_error_string = NULL;
+
+ return str;
+}
+
+const gchar *g_module_name(GModule *module)
+{
+ if (module == NULL)
+ return NULL;
+
+ return module->file_name;
+}
diff --git a/utils/eglib/gmodule.h b/utils/eglib/gmodule.h
new file mode 100644
index 00000000..e392d5c8
--- /dev/null
+++ b/utils/eglib/gmodule.h
@@ -0,0 +1,21 @@
+#ifndef __GMODULE_H
+#define __GMODULE_H
+
+#include <gmain.h>
+
+typedef struct _GModule GModule;
+
+typedef enum {
+ G_MODULE_BIND_LAZY = 1 << 0,
+ G_MODULE_BIND_LOCAL = 1 << 1,
+ G_MODULE_BIND_MASK = 0x03
+} GModuleFlags;
+
+GModule *g_module_open(const gchar *file_name, GModuleFlags flags);
+gboolean g_module_symbol(GModule *module, const gchar *symbol_name,
+ gpointer *symbol);
+const gchar *g_module_name(GModule *module);
+gboolean g_module_close(GModule *module);
+const gchar *g_module_error(void);
+
+#endif /* __GMODULE_H */
diff --git a/utils/gdbus/Makefile.am b/utils/gdbus/Makefile.am
new file mode 100644
index 00000000..9447555f
--- /dev/null
+++ b/utils/gdbus/Makefile.am
@@ -0,0 +1,8 @@
+
+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/utils/gdbus/Makefile.in b/utils/gdbus/Makefile.in
new file mode 100644
index 00000000..f336ce53
--- /dev/null
+++ b/utils/gdbus/Makefile.in
@@ -0,0 +1,458 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = gdbus
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libgdbus_la_LIBADD =
+am_libgdbus_la_OBJECTS = mainloop.lo object.lo watch.lo
+libgdbus_la_OBJECTS = $(am_libgdbus_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libgdbus_la_SOURCES)
+DIST_SOURCES = $(libgdbus_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libgdbus.la
+libgdbus_la_SOURCES = gdbus.h mainloop.c object.c watch.c
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gdbus/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gdbus/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgdbus.la: $(libgdbus_la_OBJECTS) $(libgdbus_la_DEPENDENCIES)
+ $(LINK) $(libgdbus_la_OBJECTS) $(libgdbus_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mainloop.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watch.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/gdbus/gdbus.h b/utils/gdbus/gdbus.h
new file mode 100644
index 00000000..eefd3734
--- /dev/null
+++ b/utils/gdbus/gdbus.h
@@ -0,0 +1,126 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 __GDBUS_H
+#define __GDBUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+typedef void (* GDBusWatchFunction) (void *user_data);
+
+DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
+ DBusError *error);
+
+gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
+ GDBusWatchFunction function,
+ void *user_data, DBusFreeFunction destroy);
+
+typedef void (* GDBusDestroyFunction) (void *user_data);
+
+typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
+ DBusMessage *message, void *user_data);
+
+typedef enum {
+ G_DBUS_METHOD_FLAG_DEPRECATED = (1 << 0),
+ G_DBUS_METHOD_FLAG_NOREPLY = (1 << 1),
+ G_DBUS_METHOD_FLAG_ASYNC = (1 << 2),
+} GDBusMethodFlags;
+
+typedef enum {
+ G_DBUS_SIGNAL_FLAG_DEPRECATED = (1 << 0),
+} GDBusSignalFlags;
+
+typedef enum {
+ G_DBUS_PROPERTY_FLAG_DEPRECATED = (1 << 0),
+} GDBusPropertyFlags;
+
+typedef struct {
+ const char *name;
+ const char *signature;
+ const char *reply;
+ GDBusMethodFunction function;
+ GDBusMethodFlags flags;
+} GDBusMethodTable;
+
+typedef struct {
+ const char *name;
+ const char *signature;
+ GDBusSignalFlags flags;
+} GDBusSignalTable;
+
+typedef struct {
+ const char *name;
+ const char *type;
+ GDBusPropertyFlags flags;
+} GDBusPropertyTable;
+
+gboolean g_dbus_register_interface(DBusConnection *connection,
+ const char *path, const char *name,
+ GDBusMethodTable *methods,
+ GDBusSignalTable *signals,
+ GDBusPropertyTable *properties,
+ void *user_data,
+ GDBusDestroyFunction destroy);
+gboolean g_dbus_unregister_interface(DBusConnection *connection,
+ const char *path, const char *name);
+gboolean g_dbus_unregister_all_interfaces(DBusConnection *connection,
+ const char *path);
+
+DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
+ const char *format, ...);
+DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
+ const char *format, va_list args);
+DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...);
+DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
+ int type, va_list args);
+
+gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message);
+gboolean g_dbus_send_reply(DBusConnection *connection,
+ DBusMessage *message, int type, ...);
+gboolean g_dbus_send_reply_valist(DBusConnection *connection,
+ DBusMessage *message, int type, va_list args);
+
+gboolean g_dbus_emit_signal(DBusConnection *connection,
+ const char *path, const char *interface,
+ const char *name, int type, ...);
+gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
+ const char *path, const char *interface,
+ const char *name, int type, va_list args);
+
+guint g_dbus_add_disconnect_watch(DBusConnection *connection,
+ const char *name,
+ GDBusWatchFunction function,
+ void *user_data, GDBusDestroyFunction destroy);
+gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag);
+void g_dbus_remove_all_watches(DBusConnection *connection);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GDBUS_H */
diff --git a/utils/gdbus/mainloop.c b/utils/gdbus/mainloop.c
new file mode 100644
index 00000000..ddcacedc
--- /dev/null
+++ b/utils/gdbus/mainloop.c
@@ -0,0 +1,299 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#ifdef NEED_DBUS_WATCH_GET_UNIX_FD
+#define dbus_watch_get_unix_fd dbus_watch_get_fd
+#endif
+
+#include "gdbus.h"
+
+#define DISPATCH_TIMEOUT 0
+
+#define info(fmt...)
+#define error(fmt...)
+#define debug(fmt...)
+
+typedef struct {
+ uint32_t id;
+ DBusTimeout *timeout;
+} timeout_handler_t;
+
+struct watch_info {
+ guint watch_id;
+ GIOChannel *io;
+ DBusConnection *conn;
+};
+
+struct server_info {
+ guint watch_id;
+ GIOChannel *io;
+ DBusServer *server;
+};
+
+struct disconnect_data {
+ void (*disconnect_cb)(void *);
+ void *user_data;
+};
+
+static DBusHandlerResult disconnect_filter(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");
+ dbus_connection_unref(conn);
+ dc_data->disconnect_cb(dc_data->user_data);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean message_dispatch_cb(void *data)
+{
+ DBusConnection *connection = data;
+
+ dbus_connection_ref(connection);
+
+ /* Dispatch messages */
+ while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+
+ dbus_connection_unref(connection);
+
+ return FALSE;
+}
+
+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;
+
+ 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);
+
+ if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS)
+ g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn);
+
+ return TRUE;
+}
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data)
+{
+ GIOCondition cond = G_IO_HUP | G_IO_ERR;
+ DBusConnection *conn = data;
+ struct watch_info *info;
+ int fd, flags;
+
+ if (!dbus_watch_get_enabled(watch))
+ return TRUE;
+
+ info = g_new(struct watch_info, 1);
+
+ fd = dbus_watch_get_unix_fd(watch);
+ info->io = g_io_channel_unix_new(fd);
+ info->conn = dbus_connection_ref(conn);
+
+ dbus_watch_set_data(watch, info, NULL);
+
+ 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);
+
+ return TRUE;
+}
+
+static void remove_watch(DBusWatch *watch, void *data)
+{
+ struct watch_info *info = dbus_watch_get_data(watch);
+
+ 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)
+{
+ /* Because we just exit on OOM, enable/disable is
+ * no different from add/remove */
+ if (dbus_watch_get_enabled(watch))
+ add_watch(watch, data);
+ else
+ remove_watch(watch, data);
+}
+
+static gboolean timeout_handler_dispatch(gpointer data)
+{
+ timeout_handler_t *handler = data;
+
+ /* if not enabled should not be polled by the main loop */
+ if (dbus_timeout_get_enabled(handler->timeout) != TRUE)
+ return FALSE;
+
+ dbus_timeout_handle(handler->timeout);
+
+ return FALSE;
+}
+
+static void timeout_handler_free(void *data)
+{
+ timeout_handler_t *handler = data;
+ if (!handler)
+ return;
+
+ g_source_remove(handler->id);
+ g_free(handler);
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
+{
+ timeout_handler_t *handler;
+
+ if (!dbus_timeout_get_enabled(timeout))
+ return TRUE;
+
+ handler = g_new0(timeout_handler_t, 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);
+
+ return TRUE;
+}
+
+static void remove_timeout(DBusTimeout *timeout, void *data)
+{
+}
+
+static void timeout_toggled(DBusTimeout *timeout, void *data)
+{
+ if (dbus_timeout_get_enabled(timeout))
+ add_timeout(timeout, data);
+ else
+ remove_timeout(timeout, data);
+}
+
+static void dispatch_status_cb(DBusConnection *conn,
+ DBusDispatchStatus new_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);
+}
+
+static 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);
+
+ dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
+ conn, NULL);
+}
+
+DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
+ DBusError *error)
+{
+ DBusConnection *conn;
+
+ conn = dbus_bus_get(type, error);
+
+ if (error != NULL) {
+ if (dbus_error_is_set(error) == TRUE)
+ return NULL;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ setup_dbus_with_main_loop(conn);
+
+ return conn;
+}
+
+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->disconnect_cb = 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");
+ g_free(dc_data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/utils/gdbus/object.c b/utils/gdbus/object.c
new file mode 100644
index 00000000..09a841e5
--- /dev/null
+++ b/utils/gdbus/object.c
@@ -0,0 +1,660 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gdbus.h"
+
+#define info(fmt...)
+#define error(fmt...)
+#define debug(fmt...)
+
+struct generic_data {
+ unsigned int refcount;
+ GSList *interfaces;
+ char *introspect;
+};
+
+struct interface_data {
+ char *name;
+ GDBusMethodTable *methods;
+ GDBusSignalTable *signals;
+ GDBusPropertyTable *properties;
+ void *user_data;
+ GDBusDestroyFunction destroy;
+};
+
+static void print_arguments(GString *gstr, const char *sig,
+ const char *direction)
+{
+ int i;
+
+ for (i = 0; sig[i]; i++) {
+ char type[32];
+ int len, struct_level, dict_level;
+ gboolean complete;
+
+ complete = FALSE;
+ struct_level = dict_level = 0;
+ memset(type, 0, sizeof(type));
+
+ /* Gather enough data to have a single complete type */
+ for (len = 0; len < (sizeof(type) - 1) && sig[i]; len++, i++) {
+ switch (sig[i]){
+ case '(':
+ struct_level++;
+ break;
+ case ')':
+ struct_level--;
+ if (struct_level <= 0 && dict_level <= 0)
+ complete = TRUE;
+ break;
+ case '{':
+ dict_level++;
+ break;
+ case '}':
+ dict_level--;
+ if (struct_level <= 0 && dict_level <= 0)
+ complete = TRUE;
+ break;
+ case 'a':
+ break;
+ default:
+ if (struct_level <= 0 && dict_level <= 0)
+ complete = TRUE;
+ break;
+ }
+
+ type[len] = sig[i];
+
+ if (complete)
+ break;
+ }
+
+
+ if (direction)
+ g_string_append_printf(gstr,
+ "\t\t\t<arg type=\"%s\" direction=\"%s\"/>\n",
+ type, direction);
+ else
+ g_string_append_printf(gstr,
+ "\t\t\t<arg type=\"%s\"/>\n",
+ type);
+ }
+}
+
+static void generate_interface_xml(GString *gstr, struct interface_data *iface)
+{
+ GDBusMethodTable *method;
+ GDBusSignalTable *signal;
+
+ for (method = iface->methods; method && method->name; method++) {
+ if (!strlen(method->signature) && !strlen(method->reply))
+ g_string_append_printf(gstr, "\t\t<method name=\"%s\"/>\n",
+ method->name);
+ else {
+ g_string_append_printf(gstr, "\t\t<method name=\"%s\">\n",
+ method->name);
+ print_arguments(gstr, method->signature, "in");
+ print_arguments(gstr, method->reply, "out");
+ g_string_append_printf(gstr, "\t\t</method>\n");
+ }
+ }
+
+ for (signal = iface->signals; signal && signal->name; signal++) {
+ if (!strlen(signal->signature))
+ g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
+ signal->name);
+ else {
+ g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
+ signal->name);
+ print_arguments(gstr, signal->signature, NULL);
+ g_string_append_printf(gstr, "\t\t</signal>\n");
+ }
+ }
+}
+
+static void generate_introspection_xml(DBusConnection *conn,
+ struct generic_data *data, const char *path)
+{
+ GSList *list;
+ GString *gstr;
+ char **children;
+ int i;
+
+ g_free(data->introspect);
+
+ gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
+
+ g_string_append_printf(gstr, "<node name=\"%s\">\n", path);
+
+ for (list = data->interfaces; list; list = list->next) {
+ struct interface_data *iface = list->data;
+
+ g_string_append_printf(gstr, "\t<interface name=\"%s\">\n",
+ iface->name);
+
+ generate_interface_xml(gstr, iface);
+
+ g_string_append_printf(gstr, "\t</interface>\n");
+ }
+
+ if (!dbus_connection_list_registered(conn, path, &children))
+ goto done;
+
+ for (i = 0; children[i]; i++)
+ g_string_append_printf(gstr, "\t<node name=\"%s\"/>\n",
+ children[i]);
+
+ dbus_free_string_array(children);
+
+done:
+ g_string_append_printf(gstr, "</node>\n");
+
+ data->introspect = g_string_free(gstr, FALSE);
+}
+
+static DBusHandlerResult introspect(DBusConnection *connection,
+ DBusMessage *message, struct generic_data *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;
+ }
+
+ if (!data->introspect)
+ generate_introspection_xml(connection, data,
+ dbus_message_get_path(message));
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ 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;
+}
+
+static void generic_unregister(DBusConnection *connection, void *user_data)
+{
+ struct generic_data *data = user_data;
+
+ g_free(data->introspect);
+ g_free(data);
+}
+
+static struct interface_data *find_interface(GSList *interfaces,
+ const char *name)
+{
+ GSList *list;
+
+ for (list = interfaces; list; list = list->next) {
+ struct interface_data *iface = list->data;
+ if (!strcmp(name, iface->name))
+ return iface;
+ }
+
+ return NULL;
+}
+
+static DBusHandlerResult generic_message(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct generic_data *data = user_data;
+ struct interface_data *iface;
+ 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);
+ if (!iface)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ for (method = iface->methods; method &&
+ method->name && method->function; method++) {
+ DBusMessage *reply;
+
+ if (dbus_message_is_method_call(message, iface->name,
+ method->name) == FALSE)
+ continue;
+
+ if (dbus_message_has_signature(message,
+ method->signature) == FALSE)
+ continue;
+
+ reply = method->function(connection, message, iface->user_data);
+
+ if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
+ if (reply != NULL)
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
+ if (reply == NULL)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (reply == NULL)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable generic_table = {
+ .unregister_function = generic_unregister,
+ .message_function = generic_message,
+};
+
+static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
+{
+ struct generic_data *data = NULL;
+ char *parent_path, *slash;
+
+ parent_path = g_strdup(child_path);
+ slash = strrchr(parent_path, '/');
+ if (!slash)
+ goto done;
+
+ *slash = '\0';
+ if (!strlen(parent_path))
+ goto done;
+
+ if (!dbus_connection_get_object_path_data(conn, parent_path,
+ (void *) &data))
+ goto done;
+
+ if (!data)
+ goto done;
+
+ g_free(data->introspect);
+ data->introspect = NULL;
+
+done:
+ g_free(parent_path);
+}
+
+static struct generic_data *object_path_ref(DBusConnection *connection,
+ const char *path)
+{
+ struct generic_data *data;
+
+ if (dbus_connection_get_object_path_data(connection, path,
+ (void *) &data) == TRUE) {
+ if (data != NULL) {
+ data->refcount++;
+ return data;
+ }
+ }
+
+ data = g_new0(struct generic_data, 1);
+
+ data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
+
+ data->refcount = 1;
+
+ if (!dbus_connection_register_object_path(connection, path,
+ &generic_table, data)) {
+ g_free(data->introspect);
+ g_free(data);
+ return NULL;
+ }
+
+ invalidate_parent_data(connection, path);
+
+ return data;
+}
+
+static void object_path_unref(DBusConnection *connection, const char *path)
+{
+ struct generic_data *data = NULL;
+
+ if (dbus_connection_get_object_path_data(connection, path,
+ (void *) &data) == FALSE)
+ return;
+
+ if (data == NULL)
+ return;
+
+ data->refcount--;
+
+ if (data->refcount > 0)
+ return;
+
+ invalidate_parent_data(connection, path);
+
+ dbus_connection_unregister_object_path(connection, path);
+}
+
+static gboolean check_signal(DBusConnection *conn, const char *path,
+ const char *interface, const char *name,
+ const char **args)
+{
+ struct generic_data *data = NULL;
+ struct interface_data *iface;
+ GDBusSignalTable *signal;
+
+ *args = NULL;
+ if (!dbus_connection_get_object_path_data(conn, path,
+ (void *) &data) || !data) {
+ error("dbus_connection_emit_signal: path %s isn't registered",
+ path);
+ return FALSE;
+ }
+
+ iface = find_interface(data->interfaces, interface);
+
+ if (!iface) {
+ error("dbus_connection_emit_signal: %s does not implement %s",
+ path, interface);
+ return FALSE;
+ }
+
+ for (signal = iface->signals; signal && signal->name; signal++) {
+ if (!strcmp(signal->name, name)) {
+ *args = signal->signature;
+ break;
+ }
+ }
+
+ if (!*args) {
+ error("No signal named %s on interface %s", name, interface);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static dbus_bool_t emit_signal_valist(DBusConnection *conn,
+ const char *path,
+ const char *interface,
+ const char *name,
+ int first,
+ va_list var_args)
+{
+ DBusMessage *signal;
+ dbus_bool_t ret;
+ const char *signature, *args;
+
+ if (!check_signal(conn, path, interface, name, &args))
+ return FALSE;
+
+ signal = dbus_message_new_signal(path, interface, name);
+ if (!signal) {
+ error("Unable to allocate new %s.%s signal", interface, name);
+ return FALSE;
+ }
+
+ ret = dbus_message_append_args_valist(signal, first, var_args);
+ if (!ret)
+ goto fail;
+
+ signature = dbus_message_get_signature(signal);
+ if (strcmp(args, signature) != 0) {
+ error("%s.%s: expected signature'%s' but got '%s'",
+ interface, name, args, signature);
+ ret = FALSE;
+ goto fail;
+ }
+
+ ret = dbus_connection_send(conn, signal, NULL);
+
+fail:
+ dbus_message_unref(signal);
+
+ return ret;
+}
+
+gboolean g_dbus_register_interface(DBusConnection *connection,
+ const char *path, const char *name,
+ GDBusMethodTable *methods,
+ GDBusSignalTable *signals,
+ 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))
+ 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);
+
+ g_free(data->introspect);
+ data->introspect = NULL;
+
+ return TRUE;
+}
+
+gboolean g_dbus_unregister_interface(DBusConnection *connection,
+ const char *path, const char *name)
+{
+ struct generic_data *data = NULL;
+ struct interface_data *iface;
+
+ if (dbus_connection_get_object_path_data(connection, path,
+ (void *) &data) == FALSE)
+ return FALSE;
+
+ if (data == NULL)
+ return FALSE;
+
+ 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);
+
+ g_free(data->introspect);
+ data->introspect = NULL;
+
+ object_path_unref(connection, path);
+
+ return TRUE;
+}
+
+gboolean g_dbus_unregister_all_interfaces(DBusConnection *connection,
+ const char *path)
+{
+ struct generic_data *data = NULL;
+
+ if (dbus_connection_get_object_path_data(connection, path,
+ (void *) &data) == FALSE)
+ return FALSE;
+
+ if (data == NULL)
+ return FALSE;
+
+ invalidate_parent_data(connection, path);
+
+ dbus_connection_unregister_object_path(connection, path);
+
+ return TRUE;
+}
+
+DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
+ const char *format, va_list args)
+{
+ return dbus_message_new_error(message, name, format);
+}
+
+DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
+ const char *format, ...)
+{
+ va_list args;
+ DBusMessage *reply;
+
+ va_start(args, format);
+
+ reply = g_dbus_create_error_valist(message, name, format, args);
+
+ va_end(args);
+
+ return reply;
+}
+
+DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
+ int type, va_list args)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL)
+ return NULL;
+
+ if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
+ dbus_message_unref(reply);
+ return NULL;
+ }
+
+ return reply;
+}
+
+DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
+{
+ va_list args;
+ DBusMessage *reply;
+
+ va_start(args, type);
+
+ reply = g_dbus_create_reply_valist(message, type, args);
+
+ va_end(args);
+
+ return reply;
+}
+
+gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
+{
+ dbus_bool_t result;
+
+ result = dbus_connection_send(connection, message, NULL);
+
+ dbus_message_unref(message);
+
+ return result;
+}
+
+gboolean g_dbus_send_reply_valist(DBusConnection *connection,
+ DBusMessage *message, int type, va_list args)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL)
+ return FALSE;
+
+ if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
+ dbus_message_unref(reply);
+ return FALSE;
+ }
+
+ return g_dbus_send_message(connection, reply);
+}
+
+gboolean g_dbus_send_reply(DBusConnection *connection,
+ DBusMessage *message, int type, ...)
+{
+ va_list args;
+ gboolean result;
+
+ va_start(args, type);
+
+ result = g_dbus_send_reply_valist(connection, message, type, args);
+
+ va_end(args);
+
+ return result;
+}
+
+gboolean g_dbus_emit_signal(DBusConnection *connection,
+ const char *path, const char *interface,
+ const char *name, int type, ...)
+{
+ va_list args;
+ gboolean result;
+
+ va_start(args, type);
+
+ result = emit_signal_valist(connection, path, interface,
+ name, type, args);
+
+ va_end(args);
+
+ return result;
+}
+
+gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
+ const char *path, const char *interface,
+ const char *name, int type, va_list args)
+{
+ return emit_signal_valist(connection, path, interface,
+ name, type, args);
+}
diff --git a/utils/gdbus/watch.c b/utils/gdbus/watch.c
new file mode 100644
index 00000000..b451cb00
--- /dev/null
+++ b/utils/gdbus/watch.c
@@ -0,0 +1,346 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gdbus.h"
+
+#define info(fmt...)
+#define error(fmt...)
+#define debug(fmt...)
+
+static guint listener_id = 0;
+static GSList *name_listeners = NULL;
+
+struct name_callback {
+ GDBusWatchFunction func;
+ void *user_data;
+ guint id;
+};
+
+struct name_data {
+ DBusConnection *connection;
+ char *name;
+ GSList *callbacks;
+};
+
+static struct name_data *name_data_find(DBusConnection *connection,
+ const char *name)
+{
+ GSList *current;
+
+ for (current = name_listeners;
+ current != NULL; current = current->next) {
+ struct name_data *data = current->data;
+
+ if (name == NULL && data->name == NULL) {
+ if (connection == data->connection)
+ return data;
+ } else {
+ if (strcmp(name, data->name) == 0)
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+static struct name_callback *name_callback_find(GSList *callbacks,
+ GDBusWatchFunction func, void *user_data)
+{
+ GSList *current;
+
+ for (current = callbacks; current != NULL; current = current->next) {
+ struct name_callback *cb = current->data;
+ if (cb->func == func && cb->user_data == user_data)
+ return cb;
+ }
+
+ 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->func)
+ cb->func(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)
+{
+ GSList *l;
+
+ for (l = data->callbacks; l != NULL; l = l->next)
+ g_free(l->data);
+
+ g_slist_free(data->callbacks);
+ g_free(data->name);
+ g_free(data);
+}
+
+static int name_data_add(DBusConnection *connection, const char *name,
+ GDBusWatchFunction func, void *user_data, guint id)
+{
+ int first = 1;
+ struct name_data *data = NULL;
+ struct name_callback *cb = NULL;
+
+ cb = g_new(struct name_callback, 1);
+
+ cb->func = func;
+ cb->user_data = user_data;
+ cb->id = 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:
+ data->callbacks = g_slist_append(data->callbacks, cb);
+ return first;
+}
+
+static void name_data_remove(DBusConnection *connection,
+ const char *name, GDBusWatchFunction func, void *user_data)
+{
+ struct name_data *data;
+ struct name_callback *cb = NULL;
+
+ data = name_data_find(connection, name);
+ if (!data)
+ return;
+
+ cb = name_callback_find(data->callbacks, func, user_data);
+ if (cb) {
+ data->callbacks = g_slist_remove(data->callbacks, cb);
+ g_free(cb);
+ }
+
+ if (!data->callbacks) {
+ name_listeners = g_slist_remove(name_listeners, data);
+ name_data_free(data);
+ }
+}
+
+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;
+ }
+
+ 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,
+ DBusMessage *message, void *user_data)
+{
+ GSList *l;
+ struct name_data *data;
+ char *name, *old, *new;
+
+ if (!dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new,
+ DBUS_TYPE_INVALID)) {
+ error("Invalid arguments for NameOwnerChanged signal");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ /* We are not interested of service creations */
+ if (*new != '\0')
+ 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;
+ }
+
+ for (l = data->callbacks; l != NULL; l = l->next) {
+ struct name_callback *cb = l->data;
+ cb->func(cb->user_data);
+ }
+
+ name_listeners = g_slist_remove(name_listeners, data);
+ name_data_free(data);
+
+ remove_match(connection, name);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+guint g_dbus_add_disconnect_watch(DBusConnection *connection,
+ const char *name,
+ GDBusWatchFunction func,
+ void *user_data, GDBusDestroyFunction destroy)
+{
+ int first;
+
+ if (!listener_id) {
+ if (!dbus_connection_add_filter(connection,
+ name_exit_filter, NULL, NULL)) {
+ error("dbus_connection_add_filter() failed");
+ return 0;
+ }
+ }
+
+ listener_id++;
+ first = name_data_add(connection, name, func, 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;
+
+ if (name) {
+ debug("name_listener_add(%s)", name);
+
+ if (!add_match(connection, name)) {
+ name_data_remove(connection, name, func, user_data);
+ return 0;
+ }
+ }
+
+ return listener_id;
+}
+
+gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
+{
+ struct name_data *data;
+ struct name_callback *cb;
+ GSList *ldata, *lcb;
+
+ if (id == 0)
+ return FALSE;
+
+ for (ldata = name_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;
+ }
+ }
+
+ return FALSE;
+
+remove:
+ data->callbacks = g_slist_remove(data->callbacks, cb);
+ g_free(cb);
+
+ /* Don't remove the filter if other callbacks exist */
+ if (data->callbacks)
+ 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);
+
+ return TRUE;
+}
+
+void g_dbus_remove_all_watches(DBusConnection *connection)
+{
+ struct name_data *data;
+
+ data = name_data_find(connection, NULL);
+ if (!data) {
+ error("name_listener_indicate_disconnect: no listener found");
+ return;
+ }
+
+ debug("name_listener_indicate_disconnect");
+
+ name_data_call_and_free(data);
+}
diff --git a/utils/hcid/Makefile.am b/utils/hcid/Makefile.am
new file mode 100644
index 00000000..763374f1
--- /dev/null
+++ b/utils/hcid/Makefile.am
@@ -0,0 +1,64 @@
+
+if CONFIGFILES
+dbusdir = $(sysconfdir)/dbus-1/system.d
+
+dbus_DATA = bluetooth.conf
+
+confdir = $(sysconfdir)/bluetooth
+
+conf_DATA = hcid.conf
+
+statedir = $(localstatedir)/lib/bluetooth
+
+state_DATA =
+endif
+
+noinst_LIBRARIES = libhciserver.a
+
+libhciserver_a_SOURCES = hcid.h security.c storage.c \
+ parser.h parser.y lexer.l kword.c kword.h \
+ server.h server.c manager.h manager.c \
+ adapter.h adapter.c device.h device.c plugin.h plugin.c \
+ dbus-common.c dbus-common.h dbus-error.c dbus-error.h \
+ dbus-database.c dbus-database.h dbus-security.c dbus-security.h \
+ dbus-service.c dbus-service.h \
+ dbus-hci.h dbus-hci.c dbus-sdp.c dbus-sdp.h \
+ telephony.h telephony.c agent.h agent.c
+
+sbin_PROGRAMS = hcid
+
+hcid_SOURCES = main.c
+
+hcid_LDADD = libhciserver.a \
+ $(top_builddir)/sdpd/libsdpserver.a \
+ $(top_builddir)/common/libhelper.a \
+ @GDBUS_LIBS@ @GMODULE_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+if MAINTAINER_MODE
+plugindir = $(abs_top_srcdir)/plugins
+else
+plugindir = $(libdir)/bluetooth/plugins
+endif
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ \
+ @GLIB_CFLAGS@ @GMODULE_CFLAGS@ @GDBUS_CFLAGS@ \
+ -DPLUGINDIR=\""$(plugindir)"\"
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/sdpd
+
+BUILT_SOURCES = parser.h
+
+if MANPAGES
+man_MANS = hcid.8 hcid.conf.5
+endif
+
+AM_YFLAGS = -d
+
+CLEANFILES = lexer.c parser.c parser.h
+
+EXTRA_DIST = bluetooth.conf hcid.8 hcid.conf.5 hcid.conf dbus-api.txt \
+ list-devices test-discovery test-manager test-adapter test-device \
+ simple-service simple-agent service-record.dtd \
+ service-did.xml service-spp.xml service-opp.xml service-ftp.xml
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/hcid/Makefile.in b/utils/hcid/Makefile.in
new file mode 100644
index 00000000..1e4870f3
--- /dev/null
+++ b/utils/hcid/Makefile.in
@@ -0,0 +1,755 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = hcid$(EXEEXT)
+subdir = hcid
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in lexer.c \
+ parser.c parser.h
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libhciserver_a_AR = $(AR) $(ARFLAGS)
+libhciserver_a_LIBADD =
+am_libhciserver_a_OBJECTS = security.$(OBJEXT) storage.$(OBJEXT) \
+ parser.$(OBJEXT) lexer.$(OBJEXT) kword.$(OBJEXT) \
+ server.$(OBJEXT) manager.$(OBJEXT) adapter.$(OBJEXT) \
+ device.$(OBJEXT) plugin.$(OBJEXT) dbus-common.$(OBJEXT) \
+ dbus-error.$(OBJEXT) dbus-database.$(OBJEXT) \
+ dbus-security.$(OBJEXT) dbus-service.$(OBJEXT) \
+ dbus-hci.$(OBJEXT) dbus-sdp.$(OBJEXT) telephony.$(OBJEXT) \
+ agent.$(OBJEXT)
+libhciserver_a_OBJECTS = $(am_libhciserver_a_OBJECTS)
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \
+ "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" \
+ "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(statedir)"
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(sbin_PROGRAMS)
+am_hcid_OBJECTS = main.$(OBJEXT)
+hcid_OBJECTS = $(am_hcid_OBJECTS)
+hcid_DEPENDENCIES = libhciserver.a $(top_builddir)/sdpd/libsdpserver.a \
+ $(top_builddir)/common/libhelper.a
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(LEX) $(LFLAGS) $(AM_LFLAGS)
+YLWRAP = $(top_srcdir)/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(YACC) $(YFLAGS) $(AM_YFLAGS)
+SOURCES = $(libhciserver_a_SOURCES) $(hcid_SOURCES)
+DIST_SOURCES = $(libhciserver_a_SOURCES) $(hcid_SOURCES)
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(man_MANS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+confDATA_INSTALL = $(INSTALL_DATA)
+dbusDATA_INSTALL = $(INSTALL_DATA)
+stateDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(conf_DATA) $(dbus_DATA) $(state_DATA)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@CONFIGFILES_TRUE@dbusdir = $(sysconfdir)/dbus-1/system.d
+@CONFIGFILES_TRUE@dbus_DATA = bluetooth.conf
+@CONFIGFILES_TRUE@confdir = $(sysconfdir)/bluetooth
+@CONFIGFILES_TRUE@conf_DATA = hcid.conf
+@CONFIGFILES_TRUE@statedir = $(localstatedir)/lib/bluetooth
+@CONFIGFILES_TRUE@state_DATA =
+noinst_LIBRARIES = libhciserver.a
+libhciserver_a_SOURCES = hcid.h security.c storage.c \
+ parser.h parser.y lexer.l kword.c kword.h \
+ server.h server.c manager.h manager.c \
+ adapter.h adapter.c device.h device.c plugin.h plugin.c \
+ dbus-common.c dbus-common.h dbus-error.c dbus-error.h \
+ dbus-database.c dbus-database.h dbus-security.c dbus-security.h \
+ dbus-service.c dbus-service.h \
+ dbus-hci.h dbus-hci.c dbus-sdp.c dbus-sdp.h \
+ telephony.h telephony.c agent.h agent.c
+
+hcid_SOURCES = main.c
+hcid_LDADD = libhciserver.a \
+ $(top_builddir)/sdpd/libsdpserver.a \
+ $(top_builddir)/common/libhelper.a \
+ @GDBUS_LIBS@ @GMODULE_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+@MAINTAINER_MODE_FALSE@plugindir = $(libdir)/bluetooth/plugins
+@MAINTAINER_MODE_TRUE@plugindir = $(abs_top_srcdir)/plugins
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ \
+ @GLIB_CFLAGS@ @GMODULE_CFLAGS@ @GDBUS_CFLAGS@ \
+ -DPLUGINDIR=\""$(plugindir)"\"
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/sdpd
+BUILT_SOURCES = parser.h
+@MANPAGES_TRUE@man_MANS = hcid.8 hcid.conf.5
+AM_YFLAGS = -d
+CLEANFILES = lexer.c parser.c parser.h
+EXTRA_DIST = bluetooth.conf hcid.8 hcid.conf.5 hcid.conf dbus-api.txt \
+ list-devices test-discovery test-manager test-adapter test-device \
+ simple-service simple-agent service-record.dtd \
+ service-did.xml service-spp.xml service-opp.xml service-ftp.xml
+
+MAINTAINERCLEANFILES = Makefile.in
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu hcid/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu hcid/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+parser.h: parser.c
+ @if test ! -f $@; then \
+ rm -f parser.c; \
+ $(MAKE) $(AM_MAKEFLAGS) parser.c; \
+ else :; fi
+libhciserver.a: $(libhciserver_a_OBJECTS) $(libhciserver_a_DEPENDENCIES)
+ -rm -f libhciserver.a
+ $(libhciserver_a_AR) libhciserver.a $(libhciserver_a_OBJECTS) $(libhciserver_a_LIBADD)
+ $(RANLIB) libhciserver.a
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sbindir)/$$f"; \
+ done
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+hcid$(EXEEXT): $(hcid_OBJECTS) $(hcid_DEPENDENCIES)
+ @rm -f hcid$(EXEEXT)
+ $(LINK) $(hcid_OBJECTS) $(hcid_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adapter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/agent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-database.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-hci.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sdp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-security.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-service.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kword.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/security.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/telephony.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+.l.c:
+ $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+ $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man5: $(man5_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 5*) ;; \
+ *) ext='5' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
+ done
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+install-confDATA: $(conf_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(confdir)" || $(MKDIR_P) "$(DESTDIR)$(confdir)"
+ @list='$(conf_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(confDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(confdir)/$$f'"; \
+ $(confDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(confdir)/$$f"; \
+ done
+
+uninstall-confDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(conf_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(confdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(confdir)/$$f"; \
+ done
+install-dbusDATA: $(dbus_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(dbusdir)" || $(MKDIR_P) "$(DESTDIR)$(dbusdir)"
+ @list='$(dbus_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(dbusDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(dbusdir)/$$f'"; \
+ $(dbusDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(dbusdir)/$$f"; \
+ done
+
+uninstall-dbusDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dbus_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(dbusdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(dbusdir)/$$f"; \
+ done
+install-stateDATA: $(state_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(statedir)" || $(MKDIR_P) "$(DESTDIR)$(statedir)"
+ @list='$(state_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(stateDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(statedir)/$$f'"; \
+ $(stateDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(statedir)/$$f"; \
+ done
+
+uninstall-stateDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(state_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(statedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(statedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(statedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f lexer.c
+ -rm -f parser.c
+ -rm -f parser.h
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-confDATA install-dbusDATA install-man \
+ install-stateDATA
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man: install-man5 install-man8
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-confDATA uninstall-dbusDATA uninstall-man \
+ uninstall-sbinPROGRAMS uninstall-stateDATA
+
+uninstall-man: uninstall-man5 uninstall-man8
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-confDATA \
+ install-data install-data-am install-dbusDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man5 install-man8 install-pdf install-pdf-am \
+ install-ps install-ps-am install-sbinPROGRAMS \
+ install-stateDATA install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-confDATA uninstall-dbusDATA \
+ uninstall-man uninstall-man5 uninstall-man8 \
+ uninstall-sbinPROGRAMS uninstall-stateDATA
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/hcid/adapter.c b/utils/hcid/adapter.c
new file mode 100644
index 00000000..5879627c
--- /dev/null
+++ b/utils/hcid/adapter.c
@@ -0,0 +1,4577 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+
+#include "adapter.h"
+#include "device.h"
+
+#include "textfile.h"
+#include "oui.h"
+#include "dbus-common.h"
+#include "dbus-hci.h"
+#include "dbus-sdp.h"
+#include "dbus-database.h"
+#include "dbus-service.h"
+#include "dbus-security.h"
+#include "dbus-error.h"
+#include "error.h"
+#include "glib-helper.h"
+#include "logging.h"
+#include "agent.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_NOINPUTOUTPUT 0x03
+#define IO_CAPABILITY_INVALID 0xFF
+
+struct mode_req {
+ struct adapter *adapter;
+ DBusConnection *conn; /* Connection reference */
+ DBusMessage *msg; /* Message reference */
+ uint8_t mode; /* Requested mode */
+ guint id; /* Listener id */
+};
+
+static const char *service_cls[] = {
+ "positioning",
+ "networking",
+ "rendering",
+ "capturing",
+ "object transfer",
+ "audio",
+ "telephony",
+ "information"
+};
+
+static const char *major_cls[] = {
+ "miscellaneous",
+ "computer",
+ "phone",
+ "access point",
+ "audio/video",
+ "peripheral",
+ "imaging",
+ "wearable",
+ "toy",
+ "uncategorized"
+};
+
+static const char *computer_minor_cls[] = {
+ "uncategorized",
+ "desktop",
+ "server",
+ "laptop",
+ "handheld",
+ "palm",
+ "wearable"
+};
+
+static const char *phone_minor_cls[] = {
+ "uncategorized",
+ "cellular",
+ "cordless",
+ "smart phone",
+ "modem",
+ "isdn"
+};
+
+static const char *access_point_minor_cls[] = {
+ "fully",
+ "1-17 percent",
+ "17-33 percent",
+ "33-50 percent",
+ "50-67 percent",
+ "67-83 percent",
+ "83-99 percent",
+ "not available"
+};
+
+static const char *audio_video_minor_cls[] = {
+ "uncategorized",
+ "headset",
+ "handsfree",
+ "unknown",
+ "microphone",
+ "loudspeaker",
+ "headphones",
+ "portable audio",
+ "car audio",
+ "set-top box",
+ "hifi audio",
+ "vcr",
+ "video camera",
+ "camcorder",
+ "video monitor",
+ "video display and loudspeaker",
+ "video conferencing",
+ "unknown",
+ "gaming/toy"
+};
+
+static const char *peripheral_minor_cls[] = {
+ "uncategorized",
+ "keyboard",
+ "pointing",
+ "combo"
+};
+
+#if 0
+static const char *peripheral_2_minor_cls[] = {
+ "uncategorized",
+ "joystick",
+ "gamepad",
+ "remote control",
+ "sensing",
+ "digitizer tablet",
+ "card reader"
+};
+#endif
+
+static const char *imaging_minor_cls[] = {
+ "display",
+ "camera",
+ "scanner",
+ "printer"
+};
+
+static const char *wearable_minor_cls[] = {
+ "wrist watch",
+ "pager",
+ "jacket",
+ "helmet",
+ "glasses"
+};
+
+static const char *toy_minor_cls[] = {
+ "robot",
+ "vehicle",
+ "doll",
+ "controller",
+ "game"
+};
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+}
+
+static inline DBusMessage *not_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);
+}
+
+static inline DBusMessage *not_authorized(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized",
+ "Not authorized");
+}
+
+static inline DBusMessage *unsupported_major_class(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".UnsupportedMajorClass",
+ "Unsupported Major Class");
+}
+
+static int auth_req_cmp(const void *p1, const void *p2)
+{
+ const struct pending_auth_info *pb1 = p1;
+ const bdaddr_t *bda = p2;
+
+ return bda ? bacmp(&pb1->bdaddr, bda) : -1;
+}
+
+void adapter_auth_request_replied(struct adapter *adapter, bdaddr_t *dba)
+{
+ GSList *l;
+ struct pending_auth_info *auth;
+
+ l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp);
+ if (!l)
+ return;
+
+ auth = l->data;
+
+ auth->replied = TRUE;
+}
+
+struct pending_auth_info *adapter_find_auth_request(struct adapter *adapter,
+ bdaddr_t *dba)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp);
+ if (l)
+ return l->data;
+
+ return NULL;
+}
+
+void adapter_remove_auth_request(struct adapter *adapter, bdaddr_t *dba)
+{
+ GSList *l;
+ struct pending_auth_info *auth;
+
+ l = g_slist_find_custom(adapter->auth_reqs, dba, auth_req_cmp);
+ if (!l)
+ return;
+
+ auth = l->data;
+
+ adapter->auth_reqs = g_slist_remove(adapter->auth_reqs, auth);
+
+ g_free(auth);
+}
+
+struct pending_auth_info *adapter_new_auth_request(struct adapter *adapter,
+ bdaddr_t *dba,
+ auth_type_t type)
+{
+ struct pending_auth_info *info;
+
+ debug("hcid_dbus_new_auth_request");
+
+ info = g_new0(struct pending_auth_info, 1);
+
+ bacpy(&info->bdaddr, dba);
+ info->type = type;
+ adapter->auth_reqs = g_slist_append(adapter->auth_reqs, info);
+
+ if (adapter->bonding && !bacmp(dba, &adapter->bonding->bdaddr))
+ adapter->bonding->auth_active = 1;
+
+ return info;
+}
+
+int pending_remote_name_cancel(struct adapter *adapter)
+{
+ struct remote_dev_info *dev, match;
+ GSList *l;
+ int dd, err = 0;
+
+ /* find the pending remote name request */
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, BDADDR_ANY);
+ match.name_status = NAME_REQUESTED;
+
+ l = g_slist_find_custom(adapter->found_devices, &match,
+ (GCompareFunc) found_device_cmp);
+ if (!l) /* no pending request */
+ return 0;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0)
+ return -ENODEV;
+
+ dev = l->data;
+
+ if (hci_read_remote_name_cancel(dd, &dev->bdaddr, 1000) < 0) {
+ error("Remote name cancel failed: %s(%d)", strerror(errno), errno);
+ err = -errno;
+ }
+
+ /* free discovered devices list */
+ g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+
+ hci_close_dev(dd);
+ return err;
+}
+
+static int auth_info_agent_cmp(const void *a, const void *b)
+{
+ const struct pending_auth_info *auth = a;
+ const struct agent *agent = b;
+
+ if (auth->agent == agent)
+ return 0;
+
+ return -1;
+}
+
+static void device_agent_removed(struct agent *agent, void *user_data)
+{
+ struct device *device = user_data;
+ struct pending_auth_info *auth;
+ GSList *l;
+
+ device->agent = NULL;
+
+ l = g_slist_find_custom(device->adapter->auth_reqs, agent,
+ auth_info_agent_cmp);
+ if (!l)
+ return;
+
+ auth = l->data;
+ auth->agent = NULL;
+}
+
+static struct bonding_request_info *bonding_request_new(DBusConnection *conn,
+ DBusMessage *msg,
+ struct adapter *adapter,
+ const char *address,
+ const char *agent_path,
+ uint8_t capability)
+{
+ struct bonding_request_info *bonding;
+ struct device *device;
+
+ debug("bonding_request_new(%s)", address);
+
+ if (hcid_dbus_use_experimental() && agent_path) {
+ const char *name = dbus_message_get_sender(msg);
+
+ device = adapter_get_device(conn, adapter, address);
+ if (!device)
+ return NULL;
+
+ device->agent = agent_create(adapter, name, agent_path,
+ capability,
+ device_agent_removed,
+ device);
+ debug("Temporary agent registered for hci%d/%s at %s:%s",
+ adapter->dev_id, device->address, name,
+ agent_path);
+ }
+
+ bonding = g_new0(struct bonding_request_info, 1);
+
+ bonding->conn = dbus_connection_ref(conn);
+ bonding->msg = dbus_message_ref(msg);
+ bonding->adapter = adapter;
+
+ str2ba(address, &bonding->bdaddr);
+
+ return bonding;
+}
+
+const char *mode2str(uint8_t mode)
+{
+ switch(mode) {
+ case MODE_OFF:
+ return "off";
+ case MODE_CONNECTABLE:
+ return "connectable";
+ case MODE_DISCOVERABLE:
+ return "discoverable";
+ case MODE_LIMITED:
+ return "limited";
+ default:
+ return "unknown";
+ }
+}
+
+static uint8_t on_mode(const char *addr)
+{
+ char mode[14];
+ bdaddr_t sba;
+
+ str2ba(addr, &sba);
+
+ if (read_on_mode(&sba, mode, sizeof(mode)) < 0)
+ return MODE_CONNECTABLE;
+
+ return str2mode(addr, mode);
+}
+
+uint8_t str2mode(const char *addr, const char *mode)
+{
+ if (strcasecmp("off", mode) == 0)
+ return MODE_OFF;
+ else if (strcasecmp("connectable", mode) == 0)
+ return MODE_CONNECTABLE;
+ else if (strcasecmp("discoverable", mode) == 0)
+ return MODE_DISCOVERABLE;
+ else if (strcasecmp("limited", mode) == 0)
+ return MODE_LIMITED;
+ else if (strcasecmp("on", mode) == 0)
+ return on_mode(addr);
+ else
+ return MODE_UNKNOWN;
+}
+
+static DBusMessage *adapter_get_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *property;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ bdaddr_t ba;
+ char str[249];
+ uint8_t cls[3];
+
+ if (check_address(adapter->address) < 0)
+ return adapter_not_ready(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ property = adapter->address;
+ dbus_message_iter_append_dict_entry(&dict, "address",
+ DBUS_TYPE_STRING, &property);
+
+ memset(str, 0, sizeof(str));
+ property = str;
+ str2ba(adapter->address, &ba);
+
+ if (!read_local_name(&ba, str))
+ dbus_message_iter_append_dict_entry(&dict, "name",
+ DBUS_TYPE_STRING, &property);
+
+ get_device_version(adapter->dev_id, str, sizeof(str));
+ dbus_message_iter_append_dict_entry(&dict, "version",
+ DBUS_TYPE_STRING, &property);
+
+ get_device_revision(adapter->dev_id, str, sizeof(str));
+ dbus_message_iter_append_dict_entry(&dict, "revision",
+ DBUS_TYPE_STRING, &property);
+
+ get_device_manufacturer(adapter->dev_id, str, sizeof(str));
+ dbus_message_iter_append_dict_entry(&dict, "manufacturer",
+ DBUS_TYPE_STRING, &property);
+
+ get_device_company(adapter->dev_id, str, sizeof(str));
+ dbus_message_iter_append_dict_entry(&dict, "company",
+ DBUS_TYPE_STRING, &property);
+
+ property = mode2str(adapter->mode);
+
+ dbus_message_iter_append_dict_entry(&dict, "mode",
+ DBUS_TYPE_STRING, &property);
+
+ dbus_message_iter_append_dict_entry(&dict, "discoverable_timeout",
+ DBUS_TYPE_UINT32, &adapter->discov_timeout);
+
+ if (!read_local_class(&ba, cls)) {
+ uint32_t class;
+
+ memcpy(&class, cls, 3);
+ dbus_message_iter_append_dict_entry(&dict, "class",
+ DBUS_TYPE_UINT32, &class);
+
+ property = major_class_str(class);
+ dbus_message_iter_append_dict_entry(&dict, "major_class",
+ DBUS_TYPE_STRING, &property);
+
+ property = minor_class_str(class);
+ dbus_message_iter_append_dict_entry(&dict, "minor_class",
+ DBUS_TYPE_STRING, &property);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *paddr = adapter->address;
+ DBusMessage *reply;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ if (check_address(paddr) < 0)
+ return adapter_not_ready(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_version(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char str[20], *str_ptr = str;
+ int err;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ err = get_device_version(adapter->dev_id, str, sizeof(str));
+ if (err < 0)
+ return failed_strerror(msg, -err);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_revision(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char str[64], *str_ptr = str;
+ int err;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ err = get_device_revision(adapter->dev_id, str, sizeof(str));
+ if (err < 0)
+ return failed_strerror(msg, -err);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_manufacturer(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char str[64], *str_ptr = str;
+ int err;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ err = get_device_manufacturer(adapter->dev_id, str, sizeof(str));
+ if (err < 0)
+ return failed_strerror(msg, -err);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_company(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char str[64], *str_ptr = str;
+ int err;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ err = get_device_company(adapter->dev_id, str, sizeof(str));
+ if (err < 0)
+ return failed_strerror(msg, -err);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_list_modes(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ const char *mode_ptr[] = { "off", "connectable", "discoverable", "limited" };
+ int i;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+ for (i = 0; i < 4; i++)
+ dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
+ &mode_ptr[i]);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_mode(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const struct adapter *adapter = data;
+ DBusMessage *reply = NULL;
+ const char *mode;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ mode = mode2str(adapter->mode);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *set_mode(DBusConnection *conn, DBusMessage *msg,
+ uint8_t new_mode, void *data)
+{
+ struct adapter *adapter = data;
+ uint8_t scan_enable;
+ uint8_t current_scan = adapter->scan_enable;
+ bdaddr_t local;
+ gboolean limited;
+ int err, dd;
+ const char *mode;
+
+ switch(new_mode) {
+ case MODE_OFF:
+ scan_enable = SCAN_DISABLED;
+ break;
+ case MODE_CONNECTABLE:
+ scan_enable = SCAN_PAGE;
+ break;
+ case MODE_DISCOVERABLE:
+ case MODE_LIMITED:
+ scan_enable = (SCAN_PAGE | SCAN_INQUIRY);
+ break;
+ default:
+ return invalid_args(msg);
+ }
+
+ /* Do reverse resolution in case of "on" mode */
+ mode = mode2str(new_mode);
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0)
+ return no_such_adapter(msg);
+
+ if (!adapter->up &&
+ (hcid.offmode == HCID_OFFMODE_NOSCAN ||
+ (hcid.offmode == HCID_OFFMODE_DEVDOWN &&
+ scan_enable != SCAN_DISABLED))) {
+ /* Start HCI device */
+ if (ioctl(dd, HCIDEVUP, adapter->dev_id) == 0)
+ goto done; /* on success */
+
+ if (errno != EALREADY) {
+ err = errno;
+ error("Can't init device hci%d: %s (%d)\n",
+ adapter->dev_id, strerror(errno), errno);
+
+ hci_close_dev(dd);
+ return failed_strerror(msg, err);
+ }
+ }
+
+ if (adapter->up && scan_enable == SCAN_DISABLED &&
+ hcid.offmode == HCID_OFFMODE_DEVDOWN) {
+ if (ioctl(dd, HCIDEVDOWN, adapter->dev_id) < 0) {
+ hci_close_dev(dd);
+ return failed_strerror(msg, errno);
+ }
+
+ goto done;
+ }
+
+ limited = (new_mode == MODE_LIMITED ? TRUE : FALSE);
+ err = set_limited_discoverable(dd, adapter->class, limited);
+ if (err < 0) {
+ hci_close_dev(dd);
+ return failed_strerror(msg, -err);
+ }
+
+ if (current_scan != scan_enable) {
+ struct hci_request rq;
+ uint8_t status = 0;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_WRITE_SCAN_ENABLE;
+ rq.cparam = &scan_enable;
+ rq.clen = sizeof(scan_enable);
+ rq.rparam = &status;
+ rq.rlen = sizeof(status);
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, 1000) < 0) {
+ err = errno;
+ error("Sending write scan enable command failed: %s (%d)",
+ strerror(errno), errno);
+ hci_close_dev(dd);
+ return failed_strerror(msg, err);
+ }
+
+ if (status) {
+ error("Setting scan enable failed with status 0x%02x",
+ status);
+ hci_close_dev(dd);
+ return failed_strerror(msg, bt_error(status));
+ }
+ } else {
+ /* discoverable or limited */
+ if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) {
+ g_dbus_emit_signal(conn,
+ dbus_message_get_path(msg),
+ ADAPTER_INTERFACE,
+ "ModeChanged",
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ if (adapter->timeout_id)
+ g_source_remove(adapter->timeout_id);
+
+ if (!adapter->sessions && !adapter->discov_timeout)
+ adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000,
+ discov_timeout_handler, adapter);
+ }
+ }
+done:
+ str2ba(adapter->address, &local);
+ write_device_mode(&local, mode);
+
+ hci_close_dev(dd);
+
+ adapter->mode = new_mode;
+
+ return dbus_message_new_method_return(msg);
+}
+
+gint find_session(struct mode_req *req, DBusMessage *msg)
+{
+ const char *name = dbus_message_get_sender(req->msg);
+ const char *sender = dbus_message_get_sender(msg);
+
+ return strcmp(name, sender);
+}
+
+static void confirm_mode_cb(struct agent *agent, DBusError *err, void *data)
+{
+ struct mode_req *req = data;
+ DBusMessage *reply;
+
+ if (err && dbus_error_is_set(err)) {
+ reply = dbus_message_new_error(req->msg, err->name, err->message);
+ dbus_connection_send(req->conn, reply, NULL);
+ dbus_message_unref(reply);
+ goto cleanup;
+ }
+
+ reply = set_mode(req->conn, req->msg, req->mode, req->adapter);
+ dbus_connection_send(req->conn, reply, NULL);
+ dbus_message_unref(reply);
+
+ if (!g_slist_find_custom(req->adapter->sessions, req->msg,
+ (GCompareFunc) find_session))
+ goto cleanup;
+
+ return;
+
+cleanup:
+ dbus_message_unref(req->msg);
+ if (req->id)
+ g_dbus_remove_watch(req->conn, req->id);
+ dbus_connection_unref(req->conn);
+ g_free(req);
+}
+
+static DBusMessage *confirm_mode(DBusConnection *conn, DBusMessage *msg,
+ const char *mode, void *data)
+{
+ struct adapter *adapter = data;
+ struct mode_req *req;
+ int ret;
+
+ if (!adapter->agent)
+ return dbus_message_new_method_return(msg);
+
+ req = g_new0(struct mode_req, 1);
+ req->adapter = adapter;
+ req->conn = dbus_connection_ref(conn);
+ req->msg = dbus_message_ref(msg);
+ req->mode = str2mode(adapter->address, mode);
+
+ ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb,
+ req);
+ if (ret < 0) {
+ dbus_connection_unref(req->conn);
+ dbus_message_unref(req->msg);
+ g_free(req);
+ return invalid_args(msg);
+ }
+
+ return NULL;
+}
+
+static DBusMessage *adapter_set_mode(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *mode;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (!mode)
+ return invalid_args(msg);
+
+ adapter->global_mode = str2mode(adapter->address, mode);
+
+ if (adapter->global_mode == adapter->mode)
+ return dbus_message_new_method_return(msg);
+
+ if (adapter->sessions && adapter->global_mode < adapter->mode)
+ return confirm_mode(conn, msg, mode, data);
+
+ return set_mode(conn, msg, str2mode(adapter->address, mode), data);
+}
+
+static DBusMessage *adapter_get_discoverable_to(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const struct adapter *adapter = data;
+ DBusMessage *reply;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, &adapter->discov_timeout,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static void resolve_paths(DBusMessage *msg, char **old_path, char **new_path)
+{
+ const char *path = dbus_message_get_path(msg);
+
+ if (!path)
+ return;
+
+ if (old_path)
+ *old_path = NULL;
+
+ if (new_path)
+ *new_path = NULL;
+
+ /* old path calls */
+ if (g_str_has_prefix(path, BASE_PATH)) {
+ if (old_path)
+ *old_path = g_strdup(path);
+
+ if (hcid_dbus_use_experimental() && new_path)
+ *new_path = g_strdup(path + ADAPTER_PATH_INDEX);
+
+ return;
+ }
+
+ if (old_path)
+ *old_path = g_strconcat(BASE_PATH, path, NULL);
+
+ if (new_path)
+ *new_path = g_strdup(path);
+}
+
+static DBusMessage *set_discoverable_timeout(DBusConnection *conn,
+ DBusMessage *msg,
+ uint32_t timeout,
+ void *data)
+{
+ struct adapter *adapter = data;
+ bdaddr_t bdaddr;
+ char *old_path, *new_path;
+
+ if (adapter->timeout_id) {
+ g_source_remove(adapter->timeout_id);
+ adapter->timeout_id = 0;
+ }
+
+ if ((timeout != 0) && (adapter->scan_enable & SCAN_INQUIRY))
+ adapter->timeout_id = g_timeout_add(timeout * 1000,
+ discov_timeout_handler,
+ adapter);
+
+ adapter->discov_timeout = timeout;
+
+ str2ba(adapter->address, &bdaddr);
+ write_discoverable_timeout(&bdaddr, timeout);
+
+ resolve_paths(msg, &old_path, &new_path);
+
+ g_dbus_emit_signal(conn, old_path,
+ ADAPTER_INTERFACE,
+ "DiscoverableTimeoutChanged",
+ DBUS_TYPE_UINT32, &timeout,
+ DBUS_TYPE_INVALID);
+ if (new_path) {
+ dbus_connection_emit_property_changed(conn, new_path,
+ ADAPTER_INTERFACE,
+ "DiscoverableTimeout",
+ DBUS_TYPE_UINT32, &timeout);
+ }
+
+ g_free(old_path);
+ g_free(new_path);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_set_discoverable_to(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ uint32_t timeout;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT32, &timeout,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ return set_discoverable_timeout(conn, msg, timeout, data);
+}
+
+static DBusMessage *adapter_is_connectable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const struct adapter *adapter = data;
+ DBusMessage *reply;
+ const uint8_t scan_enable = adapter->scan_enable;
+ dbus_bool_t connectable = FALSE;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ if (scan_enable & SCAN_PAGE)
+ connectable = TRUE;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connectable,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_is_discoverable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const struct adapter *adapter = data;
+ DBusMessage *reply;
+ const uint8_t scan_enable = adapter->scan_enable;
+ dbus_bool_t discoverable = FALSE;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ if (scan_enable & SCAN_INQUIRY)
+ discoverable = TRUE;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &discoverable,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_is_connected(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ dbus_bool_t connected = FALSE;
+
+ struct adapter *adapter = data;
+ GSList *l = adapter->active_conn;
+
+ const char *peer_addr;
+ bdaddr_t peer_bdaddr;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(peer_addr) < 0)
+ return invalid_args(msg);
+
+ str2ba(peer_addr, &peer_bdaddr);
+
+ l = g_slist_find_custom(l, &peer_bdaddr, active_conn_find_by_bdaddr);
+ if (l)
+ connected = TRUE;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_list_connections(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ struct adapter *adapter = data;
+ GSList *l = adapter->active_conn;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ while (l) {
+ char peer_addr[18];
+ const char *paddr = peer_addr;
+ struct active_conn_info *dev = l->data;
+
+ ba2str(&dev->bdaddr, peer_addr);
+
+ dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
+ &paddr);
+
+ l = l->next;
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_major_class(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const struct adapter *adapter = data;
+ DBusMessage *reply;
+ const char *str_ptr = "computer";
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ /* FIXME: Currently, only computer major class is supported */
+ if ((adapter->class[1] & 0x1f) != 1)
+ return unsupported_major_class(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_list_minor_classes(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const struct adapter *adapter = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ const char **minor_ptr;
+ uint8_t major_class;
+ int size, i;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ major_class = adapter->class[1] & 0x1F;
+
+ switch (major_class) {
+ case 1: /* computer */
+ minor_ptr = computer_minor_cls;
+ size = sizeof(computer_minor_cls) / sizeof(*computer_minor_cls);
+ break;
+ case 2: /* phone */
+ minor_ptr = phone_minor_cls;
+ size = sizeof(phone_minor_cls) / sizeof(*phone_minor_cls);
+ break;
+ default:
+ return unsupported_major_class(msg);
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+ for (i = 0; i < size; i++)
+ dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
+ &minor_ptr[i]);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_minor_class(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ const char *str_ptr = "";
+ uint8_t minor_class;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ /* FIXME: Currently, only computer major class is supported */
+ if ((adapter->class[1] & 0x1f) != 1)
+ return unsupported_major_class(msg);
+
+ minor_class = adapter->class[0] >> 2;
+
+ /* Validate computer minor class */
+ if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls)))
+ goto failed;
+
+ str_ptr = computer_minor_cls[minor_class];
+
+failed:
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_set_minor_class(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *minor;
+ uint32_t dev_class = 0xFFFFFFFF;
+ int i, dd;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &minor,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (!minor)
+ return invalid_args(msg);
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0)
+ return no_such_adapter(msg);
+
+ /* Currently, only computer major class is supported */
+ if ((adapter->class[1] & 0x1f) != 1) {
+ hci_close_dev(dd);
+ return unsupported_major_class(msg);
+ }
+ for (i = 0; i < sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); i++)
+ if (!strcasecmp(minor, computer_minor_cls[i])) {
+ /* Remove the format type */
+ dev_class = i << 2;
+ break;
+ }
+
+ /* Check if it's a valid minor class */
+ if (dev_class == 0xFFFFFFFF) {
+ hci_close_dev(dd);
+ return invalid_args(msg);
+ }
+
+ /* set the service class and major class */
+ dev_class |= (adapter->class[2] << 16) | (adapter->class[1] << 8);
+
+ if (hci_write_class_of_dev(dd, dev_class, 2000) < 0) {
+ int err = errno;
+ error("Can't write class of device on hci%d: %s(%d)",
+ adapter->dev_id, strerror(errno), errno);
+ hci_close_dev(dd);
+ return failed_strerror(msg, err);
+ }
+
+ g_dbus_emit_signal(conn, dbus_message_get_path(msg),
+ ADAPTER_INTERFACE, "MinorClassChanged",
+ DBUS_TYPE_STRING, &minor,
+ DBUS_TYPE_INVALID);
+
+ hci_close_dev(dd);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_get_service_classes(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ const char *str_ptr;
+ int i;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) {
+ if (adapter->class[2] & (1 << i)) {
+ str_ptr = service_cls[i];
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &str_ptr);
+ }
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char str[249], *str_ptr = str;
+ int err;
+ bdaddr_t ba;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ str2ba(adapter->address, &ba);
+
+ err = read_local_name(&ba, str);
+ if (err < 0) {
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ err = get_device_name(adapter->dev_id, str, sizeof(str));
+ if (err < 0)
+ return failed_strerror(msg, -err);
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
+ const char *name, void *data)
+{
+ struct adapter *adapter = data;
+ bdaddr_t bdaddr;
+ int ecode;
+ char *new_path;
+
+ if (!g_utf8_validate(name, -1, NULL)) {
+ error("Name change failed: the supplied name isn't valid UTF-8");
+ return invalid_args(msg);
+ }
+
+ str2ba(adapter->address, &bdaddr);
+
+ write_local_name(&bdaddr, (char *) name);
+
+ if (!adapter->up)
+ goto done;
+
+ ecode = set_device_name(adapter->dev_id, name);
+ if (ecode < 0)
+ return failed_strerror(msg, -ecode);
+done:
+ resolve_paths(msg, NULL, &new_path);
+
+ if (new_path) {
+ dbus_connection_emit_property_changed(conn, new_path,
+ ADAPTER_INTERFACE,
+ "Name", DBUS_TYPE_STRING,
+ &name);
+ }
+
+ g_free(new_path);
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_set_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ char *str_ptr;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ return set_name(conn, msg, str_ptr, data);
+}
+
+static DBusMessage *adapter_get_remote_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ bdaddr_t src, dst;
+ const char *addr_ptr;
+ char filename[PATH_MAX + 1];
+ char buf[64];
+ const char *ptr;
+ char *str;
+ dbus_bool_t boolean;
+ uint32_t class;
+ int compid, ver, subver;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ /* Name */
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "names");
+ str = textfile_caseget(filename, addr_ptr);
+ if (str) {
+ dbus_message_iter_append_dict_entry(&dict, "name",
+ DBUS_TYPE_STRING, &str);
+ free(str);
+ }
+
+ str2ba(adapter->address, &src);
+ str2ba(addr_ptr, &dst);
+
+ /* Remote device class */
+ if (read_remote_class(&src, &dst, &class) == 0) {
+
+ dbus_message_iter_append_dict_entry(&dict, "class",
+ DBUS_TYPE_UINT32, &class);
+
+ ptr = major_class_str(class);
+ dbus_message_iter_append_dict_entry(&dict, "major_class",
+ DBUS_TYPE_STRING, &ptr);
+
+ ptr = minor_class_str(class);
+ dbus_message_iter_append_dict_entry(&dict, "minor_class",
+ DBUS_TYPE_STRING, &ptr);
+ }
+
+ /* Alias */
+ if (get_device_alias(adapter->dev_id, &dst, buf, sizeof(buf)) > 0) {
+ ptr = buf;
+ dbus_message_iter_append_dict_entry(&dict, "alias",
+ DBUS_TYPE_STRING, &ptr);
+ }
+
+ /* Bonded */
+ create_name(filename, PATH_MAX, STORAGEDIR,
+ adapter->address, "linkkeys");
+ str = textfile_caseget(filename, addr_ptr);
+ if (str) {
+ boolean = TRUE;
+ free(str);
+ } else {
+ boolean = FALSE;
+ }
+
+ dbus_message_iter_append_dict_entry(&dict, "bonded",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ /* Trusted */
+ boolean = read_trust(&src, addr_ptr, GLOBAL_TRUST);
+ dbus_message_iter_append_dict_entry(&dict, "trusted",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ /* Connected */
+ if (g_slist_find_custom(adapter->active_conn, &dst,
+ active_conn_find_by_bdaddr))
+ boolean = TRUE;
+ else
+ boolean = FALSE;
+
+ dbus_message_iter_append_dict_entry(&dict, "connected",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ /* HCI Revision/Manufacturer/Version */
+ create_name(filename, PATH_MAX, STORAGEDIR,
+ adapter->address, "manufacturers");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (!str)
+ goto done;
+
+ if (sscanf(str, "%d %d %d", &compid, &ver, &subver) != 3) {
+ /* corrupted file data */
+ free(str);
+ goto done;
+ }
+
+ free(str);
+
+ ptr = buf;
+ snprintf(buf, 16, "HCI 0x%X", subver);
+ dbus_message_iter_append_dict_entry(&dict, "revision",
+ DBUS_TYPE_STRING, &ptr);
+
+ ptr = bt_compidtostr(compid);
+ dbus_message_iter_append_dict_entry(&dict, "manufacturer",
+ DBUS_TYPE_STRING, &ptr);
+
+ str = lmp_vertostr(ver);
+ snprintf(buf, 64, "Bluetooth %s", str);
+ bt_free(str);
+
+ create_name(filename, PATH_MAX, STORAGEDIR,
+ adapter->address, "features");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (str) {
+ if (strlen(str) == 16) {
+ uint8_t features;
+ /* Getting the third byte */
+ features = ((str[6] - 48) << 4) | (str[7] - 48);
+ if (features & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M))
+ snprintf(buf, 64, "Bluetooth %s + EDR", ptr);
+
+ }
+ free(str);
+ }
+ ptr = buf;
+ dbus_message_iter_append_dict_entry(&dict, "version",
+ DBUS_TYPE_STRING, &ptr);
+
+done:
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_svc(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_BINARY);
+}
+
+static DBusMessage *adapter_get_remote_svc_xml(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_XML);
+}
+
+static DBusMessage *adapter_get_remote_svc_handles(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return get_remote_svc_handles(conn, msg, data);
+}
+
+static DBusMessage *adapter_get_remote_svc_identifiers(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return get_remote_svc_identifiers(conn, msg, data);
+}
+
+static DBusMessage *adapter_finish_sdp_transact(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return finish_remote_svc_transact(conn, msg, data);
+}
+
+static DBusMessage *adapter_get_remote_version(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ char *addr_ptr, *str;
+ char *str_ver = NULL;
+ char info_array[64], *info = info_array;
+ int compid, ver, subver;
+
+ memset(info_array, 0, 64);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "manufacturers");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (!str)
+ return not_available(msg);
+
+ if (sscanf(str, "%d %d %d", &compid, &ver, &subver) != 3) {
+ /* corrupted file data */
+ free(str);
+ goto failed;
+ }
+
+ free(str);
+
+ str_ver = lmp_vertostr(ver);
+
+ /* Default value */
+ snprintf(info, 64, "Bluetooth %s", str_ver);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "features");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (!str)
+ goto failed;
+
+ /* Check if the data is not corrupted */
+ if (strlen(str) == 16) {
+ uint8_t features;
+ /* Getting the third byte */
+ features = ((str[6] - 48) << 4) | (str[7] - 48);
+ if (features & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M))
+ snprintf(info, 64, "Bluetooth %s + EDR", str_ver);
+ }
+
+ free(str);
+
+failed:
+ if (str_ver)
+ bt_free(str_ver);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &info,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_revision(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ char *addr_ptr, *str;
+ char info_array[16], *info = info_array;
+ int compid, ver, subver;
+
+ memset(info_array, 0, 16);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "manufacturers");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (!str)
+ return not_available(msg);
+
+ if (sscanf(str, "%d %d %d", &compid, &ver, &subver) == 3)
+ snprintf(info, 16, "HCI 0x%X", subver);
+
+ free(str);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &info,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_manufacturer(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ char *addr_ptr, *str;
+ char info_array[64], *info = info_array;
+ int compid, ver, subver;
+
+ memset(info_array, 0, 64);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "manufacturers");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (!str)
+ return not_available(msg);
+
+ if (sscanf(str, "%d %d %d", &compid, &ver, &subver) == 3)
+ info = bt_compidtostr(compid);
+
+ free(str);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &info,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_company(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ bdaddr_t bdaddr;
+ char oui[9], *str_bdaddr, *tmp;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &str_bdaddr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ str2ba(str_bdaddr, &bdaddr);
+ ba2oui(&bdaddr, oui);
+
+ tmp = ouitocomp(oui);
+ if (!tmp)
+ return not_available(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ free(tmp);
+ return NULL;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &tmp,
+ DBUS_TYPE_INVALID);
+
+ free(tmp);
+
+ return reply;
+}
+
+static DBusMessage *get_remote_class(DBusConnection *conn, DBusMessage *msg,
+ void *data, uint32_t *class)
+{
+ struct adapter *adapter = data;
+ char *addr_peer;
+ bdaddr_t local, peer;
+ int ecode;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_peer,
+ DBUS_TYPE_INVALID)) {
+ return invalid_args(msg);
+ }
+
+ if (check_address(addr_peer) < 0)
+ return invalid_args(msg);
+
+ str2ba(addr_peer, &peer);
+ str2ba(adapter->address, &local);
+
+ ecode = read_remote_class(&local, &peer, class);
+ if (ecode < 0)
+ return not_available(msg);
+
+ return NULL;
+}
+
+static DBusMessage *adapter_get_remote_major_class(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *major_class;
+ uint32_t class;
+
+ reply = get_remote_class(conn, msg, data, &class);
+ if (reply)
+ return reply;
+
+ major_class = major_class_str(class);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &major_class,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_minor_class(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *minor_class;
+ uint32_t class;
+
+ reply = get_remote_class(conn, msg, data, &class);
+ if (reply)
+ return reply;
+
+ minor_class = minor_class_str(class);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &minor_class,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static void append_class_string(const char *class, DBusMessageIter *iter)
+{
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &class);
+}
+
+static DBusMessage *adapter_get_remote_service_cls(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ GSList *service_classes;
+ uint32_t class;
+
+ reply = get_remote_class(conn, msg, data, &class);
+ if (reply)
+ return reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ service_classes = service_classes_str(class);
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ g_slist_foreach(service_classes, (GFunc) append_class_string,
+ &array_iter);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ g_slist_free(service_classes);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_class(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ uint32_t class;
+
+ reply = get_remote_class(conn, msg, data, &class);
+ if (reply)
+ return reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, &class,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_features(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ char filename[PATH_MAX + 1];
+ struct adapter *adapter = data;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, array_iter;
+ uint8_t features[8], *ptr = features;
+ const char *addr;
+ char *str;
+ int i;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr) < 0)
+ return invalid_args(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "features");
+
+ str = textfile_caseget(filename, addr);
+ if (!str)
+ return not_available(msg);
+
+ memset(features, 0, sizeof(features));
+ for (i = 0; i < sizeof(features); i++) {
+ char tmp[3];
+
+ memcpy(tmp, str + (i * 2), 2);
+ tmp[2] = '\0';
+
+ features[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ free(str);
+ return NULL;
+ }
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &array_iter);
+
+ dbus_message_iter_append_fixed_array(&array_iter,
+ DBUS_TYPE_BYTE, &ptr, sizeof(features));
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ free(str);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_remote_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ char filename[PATH_MAX + 1];
+ struct adapter *adapter = data;
+ DBusMessage *reply = NULL;
+ const char *peer_addr;
+ bdaddr_t peer_bdaddr;
+ char *str;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(peer_addr) < 0)
+ return invalid_args(msg);
+
+ /* check if it is in the cache */
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "names");
+
+ str = textfile_caseget(filename, peer_addr);
+
+ if (str) {
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ free(str);
+ return NULL;
+ }
+
+ /* send the cached name */
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID);
+
+ free(str);
+ return reply;
+ }
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ /* If the discover process is not running, return an error */
+ if (!adapter->discov_active && !adapter->pdiscov_active)
+ return not_available(msg);
+
+ /* Queue the request when there is a discovery running */
+ str2ba(peer_addr, &peer_bdaddr);
+ found_device_add(&adapter->found_devices, &peer_bdaddr, 0, NAME_REQUIRED);
+
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".RequestDeferred",
+ "Request Deferred");
+}
+
+static DBusMessage *adapter_get_remote_alias(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char str[249], *str_ptr = str, *addr_ptr;
+ bdaddr_t bdaddr;
+ int ecode;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ str2ba(addr_ptr, &bdaddr);
+
+ ecode = get_device_alias(adapter->dev_id, &bdaddr, str, sizeof(str));
+ if (ecode < 0)
+ return not_available(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_set_remote_alias(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ char *alias, *addr, *old_path, *new_path;
+ bdaddr_t bdaddr;
+ int ecode;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_STRING, &alias,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if ((strlen(alias) == 0) || (check_address(addr) < 0)) {
+ error("Alias change failed: Invalid parameter");
+ return invalid_args(msg);
+ }
+
+ str2ba(addr, &bdaddr);
+
+ ecode = set_device_alias(adapter->dev_id, &bdaddr, alias);
+ if (ecode < 0)
+ return failed_strerror(msg, -ecode);
+
+ resolve_paths(msg, &old_path, &new_path);
+
+ g_dbus_emit_signal(conn, old_path,
+ ADAPTER_INTERFACE, "RemoteAliasChanged",
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_STRING, &alias,
+ DBUS_TYPE_INVALID);
+
+ if (new_path) {
+ struct device *device;
+
+ device = adapter_find_device(adapter, addr);
+ if (device) {
+ dbus_connection_emit_property_changed(conn,
+ device->path, DEVICE_INTERFACE,
+ "Alias", DBUS_TYPE_STRING, &alias);
+ }
+ }
+
+ g_free(old_path);
+ g_free(new_path);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_clear_remote_alias(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ char *addr_ptr;
+ bdaddr_t bdaddr;
+ int ecode, had_alias = 1;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0) {
+ error("Alias clear failed: Invalid parameter");
+ return invalid_args(msg);
+ }
+
+ str2ba(addr_ptr, &bdaddr);
+
+ ecode = get_device_alias(adapter->dev_id, &bdaddr, NULL, 0);
+ if (ecode == -ENXIO)
+ had_alias = 0;
+
+ ecode = set_device_alias(adapter->dev_id, &bdaddr, NULL);
+ if (ecode < 0)
+ return failed_strerror(msg, -ecode);
+
+ if (had_alias)
+ g_dbus_emit_signal(conn, dbus_message_get_path(msg),
+ ADAPTER_INTERFACE,
+ "RemoteAliasCleared",
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_last_seen(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ char *addr_ptr, *str;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "lastseen");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (!str)
+ return not_available(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ free(str);
+ return NULL;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID);
+
+ free(str);
+
+ return reply;
+}
+
+static DBusMessage *adapter_last_used(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ char *addr_ptr, *str;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "lastused");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (!str)
+ return not_available(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ free(str);
+ return NULL;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID);
+
+ free(str);
+
+ return reply;
+}
+
+gboolean dc_pending_timeout_handler(void *data)
+{
+ int dd;
+ struct adapter *adapter = data;
+ struct pending_dc_info *pending_dc = adapter->pending_dc;
+ DBusMessage *reply;
+
+ dd = hci_open_dev(adapter->dev_id);
+
+ if (dd < 0) {
+ error_no_such_adapter(pending_dc->conn,
+ pending_dc->msg);
+ dc_pending_timeout_cleanup(adapter);
+ return FALSE;
+ }
+
+ /* Send the HCI disconnect command */
+ if (hci_disconnect(dd, htobs(pending_dc->conn_handle),
+ HCI_OE_USER_ENDED_CONNECTION,
+ 500) < 0) {
+ int err = errno;
+ error("Disconnect failed");
+ error_failed_errno(pending_dc->conn, pending_dc->msg, err);
+ } else {
+ reply = dbus_message_new_method_return(pending_dc->msg);
+ if (reply) {
+ dbus_connection_send(pending_dc->conn, reply, NULL);
+ dbus_message_unref(reply);
+ } else
+ error("Failed to allocate disconnect reply");
+ }
+
+ hci_close_dev(dd);
+ dc_pending_timeout_cleanup(adapter);
+
+ return FALSE;
+}
+
+void dc_pending_timeout_cleanup(struct adapter *adapter)
+{
+ dbus_connection_unref(adapter->pending_dc->conn);
+ dbus_message_unref(adapter->pending_dc->msg);
+ g_free(adapter->pending_dc);
+ adapter->pending_dc = NULL;
+}
+
+static DBusMessage *adapter_dc_remote_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ GSList *l = adapter->active_conn;
+ const char *peer_addr;
+ bdaddr_t peer_bdaddr;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(peer_addr) < 0)
+ return invalid_args(msg);
+
+ str2ba(peer_addr, &peer_bdaddr);
+
+ l = g_slist_find_custom(l, &peer_bdaddr, active_conn_find_by_bdaddr);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotConnected",
+ "Device not connected");
+
+ if (adapter->pending_dc)
+ return in_progress(msg, "Disconnection in progress");
+
+ adapter->pending_dc = g_new0(struct pending_dc_info, 1);
+
+ /* Start waiting... */
+ adapter->pending_dc->timeout_id =
+ g_timeout_add(DC_PENDING_TIMEOUT,
+ dc_pending_timeout_handler,
+ adapter);
+
+ if (!adapter->pending_dc->timeout_id) {
+ g_free(adapter->pending_dc);
+ adapter->pending_dc = NULL;
+ return NULL;
+ }
+
+ adapter->pending_dc->conn = dbus_connection_ref(conn);
+ adapter->pending_dc->msg = dbus_message_ref(msg);
+ adapter->pending_dc->conn_handle =
+ ((struct active_conn_info *) l->data)->handle;
+
+ g_dbus_emit_signal(conn, dbus_message_get_path(msg),
+ ADAPTER_INTERFACE,
+ "RemoteDeviceDisconnectRequested",
+ DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_INVALID);
+
+ return NULL;
+}
+
+static void reply_authentication_failure(struct bonding_request_info *bonding)
+{
+ DBusMessage *reply;
+ int status;
+
+ status = bonding->hci_status ?
+ bonding->hci_status : HCI_AUTHENTICATION_FAILURE;
+
+ reply = new_authentication_return(bonding->msg, status);
+ if (reply) {
+ dbus_connection_send(bonding->conn, reply, NULL);
+ dbus_message_unref(reply);
+ }
+}
+
+struct device *adapter_find_device(struct adapter *adapter, const char *dest)
+{
+ struct device *device;
+ GSList *l;
+
+ if (!adapter)
+ return NULL;
+
+ l = g_slist_find_custom(adapter->devices,
+ dest, (GCompareFunc) device_address_cmp);
+ if (!l)
+ return NULL;
+
+ device = l->data;
+
+ return device;
+}
+
+struct device *adapter_create_device(DBusConnection *conn,
+ struct adapter *adapter, const char *address)
+{
+ struct device *device;
+
+ debug("adapter_create_device(%s)", address);
+
+ device = device_create(conn, adapter, address);
+ if (!device)
+ return NULL;
+
+ device->temporary = TRUE;
+
+ adapter->devices = g_slist_append(adapter->devices, device);
+
+ return device;
+}
+
+static DBusMessage *remove_bonding(DBusConnection *conn, DBusMessage *msg,
+ const char *address, void *data)
+{
+ struct adapter *adapter = data;
+ struct device *device;
+ char path[MAX_PATH_LENGTH], filename[PATH_MAX + 1];
+ char *str;
+ bdaddr_t src, dst;
+ GSList *l;
+ int dev, err;
+ gboolean paired;
+
+ str2ba(adapter->address, &src);
+ str2ba(address, &dst);
+
+ dev = hci_open_dev(adapter->dev_id);
+ if (dev < 0 && msg)
+ return no_such_adapter(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "linkkeys");
+
+ /* textfile_del doesn't return an error when the key is not found */
+ str = textfile_caseget(filename, address);
+ paired = str ? TRUE : FALSE;
+ g_free(str);
+
+ if (!paired && msg) {
+ hci_close_dev(dev);
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Bonding does not exist");
+ }
+
+ /* Delete the link key from storage */
+ if (textfile_casedel(filename, address) < 0 && msg) {
+ hci_close_dev(dev);
+ err = errno;
+ return failed_strerror(msg, err);
+ }
+
+ /* Delete the link key from the Bluetooth chip */
+ hci_delete_stored_link_key(dev, &dst, 0, 1000);
+
+ /* find the connection */
+ l = g_slist_find_custom(adapter->active_conn, &dst,
+ active_conn_find_by_bdaddr);
+ if (l) {
+ struct active_conn_info *con = l->data;
+ /* Send the HCI disconnect command */
+ if ((hci_disconnect(dev, htobs(con->handle),
+ HCI_OE_USER_ENDED_CONNECTION, 500) < 0)
+ && msg){
+ int err = errno;
+ error("Disconnect failed");
+ hci_close_dev(dev);
+ return failed_strerror(msg, err);
+ }
+ }
+
+ hci_close_dev(dev);
+
+ if (paired) {
+ snprintf(path, MAX_PATH_LENGTH, BASE_PATH "/hci%d",
+ adapter->dev_id);
+ g_dbus_emit_signal(conn, path,
+ ADAPTER_INTERFACE, "BondingRemoved",
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+ }
+
+ device = adapter_find_device(adapter, address);
+ if (!device)
+ goto proceed;
+
+ if (paired) {
+ gboolean paired = FALSE;
+ dbus_connection_emit_property_changed(conn, device->path,
+ DEVICE_INTERFACE, "Paired",
+ DBUS_TYPE_BOOLEAN, &paired);
+ }
+
+proceed:
+ if(!msg)
+ goto done;
+
+ return dbus_message_new_method_return(msg);
+
+done:
+ return NULL;
+}
+
+
+void adapter_remove_device(DBusConnection *conn, struct adapter *adapter,
+ struct device *device)
+{
+ bdaddr_t src;
+ char path[MAX_PATH_LENGTH];
+
+ str2ba(adapter->address, &src);
+ delete_entry(&src, "profiles", device->address);
+
+ remove_bonding(conn, NULL, device->address, adapter);
+
+ if (!device->temporary) {
+ snprintf(path, MAX_PATH_LENGTH, "/hci%d", adapter->dev_id);
+ g_dbus_emit_signal(conn, path,
+ ADAPTER_INTERFACE,
+ "DeviceRemoved",
+ DBUS_TYPE_OBJECT_PATH, &device->path,
+ DBUS_TYPE_INVALID);
+ }
+
+ if (device->agent) {
+ agent_destroy(device->agent, FALSE);
+ device->agent = NULL;
+ }
+
+ adapter->devices = g_slist_remove(adapter->devices, device);
+
+ device_remove(conn, device);
+}
+
+struct device *adapter_get_device(DBusConnection *conn,
+ struct adapter *adapter, const gchar *address)
+{
+ struct device *device;
+
+ debug("adapter_get_device(%s)", address);
+
+ if (!adapter)
+ return NULL;
+
+ device = adapter_find_device(adapter, address);
+ if (device)
+ return device;
+
+ return adapter_create_device(conn, adapter, address);
+}
+
+void remove_pending_device(struct adapter *adapter)
+{
+ struct device *device;
+ char address[18];
+
+ ba2str(&adapter->bonding->bdaddr, address);
+ device = adapter_find_device(adapter, address);
+ if (!device)
+ return;
+
+ if (device->temporary)
+ adapter_remove_device(adapter->bonding->conn, adapter, device);
+}
+
+static gboolean create_bonding_conn_complete(GIOChannel *io, GIOCondition cond,
+ struct adapter *adapter)
+{
+ struct hci_request rq;
+ auth_requested_cp cp;
+ evt_cmd_status rp;
+ struct l2cap_conninfo cinfo;
+ socklen_t len;
+ int sk, dd, ret;
+
+ if (!adapter->bonding) {
+ /* If we come here it implies a bug somewhere */
+ debug("create_bonding_conn_complete: no pending bonding!");
+ g_io_channel_close(io);
+ g_io_channel_unref(io);
+ return FALSE;
+ }
+
+ if (cond & G_IO_NVAL) {
+ error_authentication_canceled(adapter->bonding->conn,
+ adapter->bonding->msg);
+ goto cleanup;
+ }
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ debug("Hangup or error on bonding IO channel");
+
+ if (!adapter->bonding->auth_active)
+ error_connection_attempt_failed(adapter->bonding->conn,
+ adapter->bonding->msg,
+ ENETDOWN);
+ else
+ reply_authentication_failure(adapter->bonding);
+
+ goto failed;
+ }
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ len = sizeof(ret);
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
+ error("Can't get socket error: %s (%d)",
+ strerror(errno), errno);
+ error_failed_errno(adapter->bonding->conn, adapter->bonding->msg,
+ errno);
+ goto failed;
+ }
+
+ if (ret != 0) {
+ if (adapter->bonding->auth_active)
+ reply_authentication_failure(adapter->bonding);
+ else
+ error_connection_attempt_failed(adapter->bonding->conn,
+ adapter->bonding->msg,
+ ret);
+ goto failed;
+ }
+
+ len = sizeof(cinfo);
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_CONNINFO, &cinfo, &len) < 0) {
+ error("Can't get connection info: %s (%d)",
+ strerror(errno), errno);
+ error_failed_errno(adapter->bonding->conn, adapter->bonding->msg,
+ errno);
+ goto failed;
+ }
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error_no_such_adapter(adapter->bonding->conn,
+ adapter->bonding->msg);
+ goto failed;
+ }
+
+ memset(&rp, 0, sizeof(rp));
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = htobs(cinfo.hci_handle);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_AUTH_REQUESTED;
+ rq.cparam = &cp;
+ rq.clen = AUTH_REQUESTED_CP_SIZE;
+ rq.rparam = &rp;
+ rq.rlen = EVT_CMD_STATUS_SIZE;
+ rq.event = EVT_CMD_STATUS;
+
+ if (hci_send_req(dd, &rq, 500) < 0) {
+ error("Unable to send HCI request: %s (%d)",
+ strerror(errno), errno);
+ error_failed_errno(adapter->bonding->conn, adapter->bonding->msg,
+ errno);
+ hci_close_dev(dd);
+ goto failed;
+ }
+
+ if (rp.status) {
+ error("HCI_Authentication_Requested failed with status 0x%02x",
+ rp.status);
+ error_failed_errno(adapter->bonding->conn, adapter->bonding->msg,
+ bt_error(rp.status));
+ hci_close_dev(dd);
+ goto failed;
+ }
+
+ hci_close_dev(dd);
+
+ adapter->bonding->auth_active = 1;
+
+ adapter->bonding->io_id = g_io_add_watch(io,
+ G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ (GIOFunc) create_bonding_conn_complete,
+ adapter);
+
+ return FALSE;
+
+failed:
+ g_io_channel_close(io);
+ remove_pending_device(adapter);
+
+cleanup:
+ g_dbus_remove_watch(adapter->bonding->conn,
+ adapter->bonding->listener_id);
+ bonding_request_free(adapter->bonding);
+ adapter->bonding = NULL;
+
+ return FALSE;
+}
+
+static void cancel_auth_request(struct pending_auth_info *auth, int dev_id)
+{
+ int dd;
+
+ if (auth->replied)
+ return;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ error("hci_open_dev: %s (%d)", strerror(errno), errno);
+ return;
+ }
+
+ switch (auth->type) {
+ case AUTH_TYPE_PINCODE:
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY,
+ 6, &auth->bdaddr);
+ break;
+ case AUTH_TYPE_CONFIRM:
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
+ 6, &auth->bdaddr);
+ break;
+ case AUTH_TYPE_PASSKEY:
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_NEG_REPLY,
+ 6, &auth->bdaddr);
+ break;
+ case AUTH_TYPE_NOTIFY:
+ /* User Notify doesn't require any reply */
+ break;
+ }
+
+ auth->replied = TRUE;
+
+ hci_close_dev(dd);
+}
+
+static void create_bond_req_exit(void *user_data)
+{
+ struct adapter *adapter = user_data;
+ struct pending_auth_info *auth;
+ char path[MAX_PATH_LENGTH];
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, adapter->dev_id);
+
+ debug("CreateConnection requestor exited before bonding was completed");
+
+ cancel_passkey_agent_requests(adapter->passkey_agents, path,
+ &adapter->bonding->bdaddr);
+ release_passkey_agents(adapter, &adapter->bonding->bdaddr);
+
+ auth = adapter_find_auth_request(adapter, &adapter->bonding->bdaddr);
+ if (auth) {
+ cancel_auth_request(auth, adapter->dev_id);
+ if (auth->agent)
+ agent_cancel(auth->agent);
+ adapter_remove_auth_request(adapter, &adapter->bonding->bdaddr);
+ }
+
+ remove_pending_device(adapter);
+
+ g_io_channel_close(adapter->bonding->io);
+ if (adapter->bonding->io_id)
+ g_source_remove(adapter->bonding->io_id);
+ bonding_request_free(adapter->bonding);
+ adapter->bonding = NULL;
+}
+
+static DBusMessage *create_bonding(DBusConnection *conn, DBusMessage *msg,
+ const char *address, const char *agent_path,
+ uint8_t capability, void *data)
+{
+ char filename[PATH_MAX + 1];
+ char *str;
+ struct adapter *adapter = data;
+ struct bonding_request_info *bonding;
+ bdaddr_t bdaddr;
+ int sk;
+
+ str2ba(address, &bdaddr);
+
+ /* check if there is a pending discover: requested by D-Bus/non clients */
+ if (adapter->discov_active || (adapter->pdiscov_active && !adapter->pinq_idle))
+ return in_progress(msg, "Discover in progress");
+
+ pending_remote_name_cancel(adapter);
+
+ if (adapter->bonding)
+ return in_progress(msg, "Bonding in progress");
+
+ if (adapter_find_auth_request(adapter, &bdaddr))
+ return in_progress(msg, "Bonding in progress");
+
+ /* check if a link key already exists */
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "linkkeys");
+
+ str = textfile_caseget(filename, address);
+ if (str) {
+ free(str);
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".AlreadyExists",
+ "Bonding already exists");
+ }
+
+ sk = l2raw_connect(adapter->address, &bdaddr);
+ if (sk < 0)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".ConnectionAttemptFailed",
+ "Connection attempt failed");
+
+ bonding = bonding_request_new(conn, msg, adapter, address, agent_path,
+ capability);
+ if (!bonding) {
+ close(sk);
+ return NULL;
+ }
+
+ bonding->io = g_io_channel_unix_new(sk);
+ bonding->io_id = g_io_add_watch(bonding->io,
+ G_IO_OUT | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ (GIOFunc) create_bonding_conn_complete,
+ adapter);
+
+ bonding->listener_id = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ create_bond_req_exit, adapter,
+ NULL);
+
+ adapter->bonding = bonding;
+
+ return NULL;
+}
+
+static DBusMessage *adapter_create_bonding(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ char *address;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ return create_bonding(conn, msg, address, NULL,
+ IO_CAPABILITY_INVALID, data);
+}
+static DBusMessage *adapter_cancel_bonding(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *address;
+ bdaddr_t bdaddr;
+ struct bonding_request_info *bonding = adapter->bonding;
+ struct pending_auth_info *auth_req;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ str2ba(address, &bdaddr);
+ if (!bonding || bacmp(&bonding->bdaddr, &bdaddr))
+ return not_in_progress(msg, "Bonding is not in progress");
+
+ if (strcmp(dbus_message_get_sender(adapter->bonding->msg),
+ dbus_message_get_sender(msg)))
+ return not_authorized(msg);
+
+ adapter->bonding->cancel = 1;
+
+ auth_req = adapter_find_auth_request(adapter, &bdaddr);
+ if (auth_req) {
+ if (auth_req->replied) {
+ /*
+ * If disconnect can't be applied and the PIN code
+ * request was already replied it doesn't make sense
+ * cancel the remote passkey: return not authorized.
+ */
+ g_io_channel_close(adapter->bonding->io);
+ return not_authorized(msg);
+ }
+
+ cancel_auth_request(auth_req, adapter->dev_id);
+ if (auth_req->agent)
+ agent_cancel(auth_req->agent);
+ adapter_remove_auth_request(adapter, &bdaddr);
+ }
+
+ g_io_channel_close(adapter->bonding->io);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_remove_bonding(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ char *address;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ return remove_bonding(conn, msg, address, data);
+}
+
+static DBusMessage *adapter_has_bonding(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ char *addr_ptr, *str;
+ dbus_bool_t result;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "linkkeys");
+
+ str = textfile_caseget(filename, addr_ptr);
+ if (str) {
+ result = TRUE;
+ free(str);
+ } else
+ result = FALSE;
+
+ reply = dbus_message_new_method_return(msg);
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &result,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static void list_bondings_do_append(char *key, char *value, void *data)
+{
+ DBusMessageIter *iter = data;
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
+}
+
+static DBusMessage *adapter_list_bondings(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "linkkeys");
+
+ reply = dbus_message_new_method_return(msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ textfile_foreach(filename, list_bondings_do_append, &array_iter);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_pin_code_length(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ bdaddr_t local, peer;
+ char *addr_ptr;
+ uint8_t length;
+ int len;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ str2ba(adapter->address, &local);
+
+ str2ba(addr_ptr, &peer);
+
+ len = read_pin_length(&local, &peer);
+ if (len < 0)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Record does not exist");
+
+ reply = dbus_message_new_method_return(msg);
+
+ length = len;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BYTE, &length,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_get_encryption_key_size(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ bdaddr_t bdaddr;
+ char *addr_ptr;
+ uint8_t size;
+ int val;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(addr_ptr) < 0)
+ return invalid_args(msg);
+
+ str2ba(addr_ptr, &bdaddr);
+
+ val = get_encryption_key_size(adapter->dev_id, &bdaddr);
+ if (val < 0)
+ return failed_strerror(msg, -val);
+
+ reply = dbus_message_new_method_return(msg);
+
+ size = val;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BYTE, &size,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static void periodic_discover_req_exit(void *user_data)
+{
+ struct adapter *adapter = user_data;
+
+ debug("PeriodicDiscovery requestor exited");
+
+ /* Cleanup the discovered devices list and send the cmd to exit from
+ * periodic inquiry or cancel remote name request. The return value can
+ * be ignored. */
+
+ cancel_periodic_discovery(adapter);
+}
+
+static DBusMessage *adapter_start_periodic(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ periodic_inquiry_cp cp;
+ struct hci_request rq;
+ struct adapter *adapter = data;
+ uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
+ uint8_t status;
+ int dd;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (dbus_message_is_method_call(msg, ADAPTER_INTERFACE,
+ "StartPeriodicDiscovery")) {
+ if (!dbus_message_has_signature(msg,
+ DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+ }
+
+ if (adapter->discov_active || adapter->pdiscov_active)
+ return in_progress(msg, "Discover in progress");
+
+ pending_remote_name_cancel(adapter);
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0)
+ return no_such_adapter(msg);
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.lap, lap, 3);
+ cp.max_period = htobs(24);
+ cp.min_period = htobs(16);
+ cp.length = 0x08;
+ cp.num_rsp = 0x00;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_PERIODIC_INQUIRY;
+ rq.cparam = &cp;
+ rq.clen = PERIODIC_INQUIRY_CP_SIZE;
+ rq.rparam = &status;
+ rq.rlen = sizeof(status);
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, 1000) < 0) {
+ int err = errno;
+ error("Unable to start periodic inquiry: %s (%d)",
+ strerror(errno), errno);
+ hci_close_dev(dd);
+ return failed_strerror(msg, err);
+ }
+
+ if (status) {
+ error("HCI_Periodic_Inquiry_Mode failed with status 0x%02x",
+ status);
+ hci_close_dev(dd);
+ return failed_strerror(msg, bt_error(status));
+ }
+
+ adapter->pdiscov_requestor = g_strdup(dbus_message_get_sender(msg));
+
+ if (adapter->pdiscov_resolve_names)
+ adapter->discov_type = PERIODIC_INQUIRY | RESOLVE_NAME;
+ else
+ adapter->discov_type = PERIODIC_INQUIRY;
+
+ hci_close_dev(dd);
+
+ /* track the request owner to cancel it automatically if the owner
+ * exits */
+ adapter->pdiscov_listener = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ periodic_discover_req_exit,
+ adapter, NULL);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_stop_periodic(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ int err;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (dbus_message_is_method_call(msg, ADAPTER_INTERFACE,
+ "StopPeriodicDiscovery")) {
+ if (!dbus_message_has_signature(msg,
+ DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+ }
+
+ if (!adapter->pdiscov_active)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotAuthorized",
+ "Not authorized");
+ /*
+ * Cleanup the discovered devices list and send the cmd to exit
+ * from periodic inquiry mode or cancel remote name request.
+ */
+ err = cancel_periodic_discovery(adapter);
+ if (err < 0) {
+ if (err == -ENODEV)
+ return no_such_adapter(msg);
+
+ else
+ return failed_strerror(msg, -err);
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_is_periodic(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ struct adapter *adapter = data;
+ dbus_bool_t active = adapter->pdiscov_active;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &active,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_set_pdiscov_resolve(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ dbus_bool_t resolve;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_BOOLEAN, &resolve,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ debug("SetPeriodicDiscoveryNameResolving(%s)",
+ resolve ? "TRUE" : "FALSE");
+
+ adapter->pdiscov_resolve_names = resolve;
+
+ if (adapter->pdiscov_active) {
+ if (resolve)
+ adapter->discov_type |= RESOLVE_NAME;
+ else
+ adapter->discov_type &= ~RESOLVE_NAME;
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_get_pdiscov_resolve(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessage *reply;
+ struct adapter *adapter = data;
+ dbus_bool_t resolve = adapter->pdiscov_resolve_names;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &resolve,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static void discover_devices_req_exit(void *user_data)
+{
+ struct adapter *adapter = user_data;
+
+ debug("DiscoverDevices requestor exited");
+
+ /* Cleanup the discovered devices list and send the command to cancel
+ * inquiry or cancel remote name request. The return can be ignored. */
+ cancel_discovery(adapter);
+}
+
+static DBusMessage *adapter_discover_devices(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *method;
+ inquiry_cp cp;
+ evt_cmd_status rp;
+ struct hci_request rq;
+ struct adapter *adapter = data;
+ uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
+ int dd;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ if (adapter->discov_active)
+ return in_progress(msg, "Discover in progress");
+
+ pending_remote_name_cancel(adapter);
+
+ if (adapter->bonding)
+ return in_progress(msg, "Bonding in progress");
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0)
+ return no_such_adapter(msg);
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.lap, lap, 3);
+ cp.length = 0x08;
+ cp.num_rsp = 0x00;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_INQUIRY;
+ rq.cparam = &cp;
+ rq.clen = INQUIRY_CP_SIZE;
+ rq.rparam = &rp;
+ rq.rlen = EVT_CMD_STATUS_SIZE;
+ rq.event = EVT_CMD_STATUS;
+
+ if (hci_send_req(dd, &rq, 500) < 0) {
+ int err = errno;
+ error("Unable to start inquiry: %s (%d)",
+ strerror(errno), errno);
+ hci_close_dev(dd);
+ return failed_strerror(msg, err);
+ }
+
+ if (rp.status) {
+ error("HCI_Inquiry command failed with status 0x%02x",
+ rp.status);
+ hci_close_dev(dd);
+ return failed_strerror(msg, bt_error(rp.status));
+ }
+
+ method = dbus_message_get_member(msg);
+ if (strcmp("DiscoverDevicesWithoutNameResolving", method) == 0)
+ adapter->discov_type |= STD_INQUIRY;
+ else
+ adapter->discov_type |= (STD_INQUIRY | RESOLVE_NAME);
+
+ adapter->discov_requestor = g_strdup(dbus_message_get_sender(msg));
+
+
+ hci_close_dev(dd);
+
+ /* track the request owner to cancel it automatically if the owner
+ * exits */
+ adapter->discov_listener = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ discover_devices_req_exit,
+ adapter, NULL);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_cancel_discovery(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ int err;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ /* is there discover pending? or discovery cancel was requested
+ * previously */
+ if (!adapter->discov_active || adapter->discovery_cancel)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotAuthorized",
+ "Not Authorized");
+
+ /* only the discover requestor can cancel the inquiry process */
+ if (!adapter->discov_requestor ||
+ strcmp(adapter->discov_requestor, dbus_message_get_sender(msg)))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotAuthorized",
+ "Not Authorized");
+
+ /* Cleanup the discovered devices list and send the cmd to cancel
+ * inquiry or cancel remote name request */
+ err = cancel_discovery(adapter);
+ if (err < 0) {
+ if (err == -ENODEV)
+ return no_such_adapter(msg);
+ else
+ return failed_strerror(msg, -err);
+ }
+
+ /* Reply before send DiscoveryCompleted */
+ adapter->discovery_cancel = dbus_message_ref(msg);
+
+ return NULL;
+}
+
+struct remote_device_list_t {
+ GSList *list;
+ time_t time;
+};
+
+static void list_remote_devices_do_append(char *key, char *value, void *data)
+{
+ struct remote_device_list_t *param = data;
+ char *address;
+ struct tm date;
+
+ if (g_slist_find_custom(param->list, key, (GCompareFunc) strcasecmp))
+ return;
+
+ if (param->time){
+ strptime(value, "%Y-%m-%d %H:%M:%S %Z", &date);
+ if (difftime(mktime(&date), param->time) < 0)
+ return;
+ }
+
+ address = g_strdup(key);
+
+ param->list = g_slist_append(param->list, address);
+}
+
+static void remote_devices_do_append(void *data, void *user_data)
+{
+ DBusMessageIter *iter = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data);
+}
+
+static DBusMessage *adapter_list_remote_devices(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ struct remote_device_list_t param = { NULL, 0 };
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ /* Add Bonded devices to the list */
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys");
+ textfile_foreach(filename, list_remote_devices_do_append, &param);
+
+ /* Add Trusted devices to the list */
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "trusts");
+ textfile_foreach(filename, list_remote_devices_do_append, &param);
+
+ /* Add Last Used devices to the list */
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastused");
+ textfile_foreach(filename, list_remote_devices_do_append, &param);
+
+ reply = dbus_message_new_method_return(msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ g_slist_foreach(param.list, remote_devices_do_append, &array_iter);
+
+ g_slist_foreach(param.list, (GFunc) free, NULL);
+ g_slist_free(param.list);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static void append_connected(struct active_conn_info *dev, GSList *list)
+{
+ char address[18];
+
+ ba2str(&dev->bdaddr, address);
+ if (g_slist_find_custom(list, address, (GCompareFunc) strcasecmp))
+ return;
+
+ list = g_slist_append(list, g_strdup(address));
+}
+
+static DBusMessage *adapter_list_recent_remote_devices(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ struct tm date;
+ const char *string;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ DBusMessage *reply;
+ char filename[PATH_MAX + 1];
+ struct remote_device_list_t param = { NULL, 0 };
+ int len;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &string,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ /* Date format is "YYYY-MM-DD HH:MM:SS GMT" */
+ len = strlen(string);
+ if (len && (strptime(string, "%Y-%m-%d %H:%M:%S", &date) == NULL))
+ return invalid_args(msg);
+
+ /* Bonded and trusted: mandatory entries(no matter the date/time) */
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "linkkeys");
+ textfile_foreach(filename, list_remote_devices_do_append, &param);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "trusts");
+ textfile_foreach(filename, list_remote_devices_do_append, &param);
+
+ /* Last seen/used: append devices since the date informed */
+ if (len)
+ param.time = mktime(&date);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastseen");
+ textfile_foreach(filename, list_remote_devices_do_append, &param);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "lastused");
+ textfile_foreach(filename, list_remote_devices_do_append, &param);
+
+ /* connected: force appending connected devices, lastused might not match */
+ g_slist_foreach(adapter->active_conn, (GFunc) append_connected, param.list);
+
+ reply = dbus_message_new_method_return(msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ g_slist_foreach(param.list, remote_devices_do_append, &array_iter);
+
+ g_slist_foreach(param.list, (GFunc) free, NULL);
+ g_slist_free(param.list);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+
+static DBusMessage *adapter_set_trusted(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ bdaddr_t local;
+ const char *address;
+ char *old_path, *new_path;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ str2ba(adapter->address, &local);
+
+ write_trust(&local, address, GLOBAL_TRUST, TRUE);
+
+ resolve_paths(msg, &old_path, &new_path);
+
+ g_dbus_emit_signal(conn, old_path,
+ ADAPTER_INTERFACE, "TrustAdded",
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+
+ if (new_path) {
+ struct device *device;
+ gboolean trust = TRUE;
+
+ device = adapter_find_device(adapter, address);
+ if (device) {
+ dbus_connection_emit_property_changed(conn,
+ device->path, DEVICE_INTERFACE,
+ "Trusted", DBUS_TYPE_BOOLEAN, &trust);
+ }
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_is_trusted(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ const char *address;
+ dbus_bool_t trusted;
+ bdaddr_t local;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ str2ba(adapter->address, &local);
+
+ trusted = read_trust(&local, address, GLOBAL_TRUST);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_BOOLEAN, &trusted,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *adapter_remove_trust(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *address;
+ bdaddr_t local;
+ char *old_path, *new_path;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ str2ba(adapter->address, &local);
+
+ write_trust(&local, address, GLOBAL_TRUST, FALSE);
+
+ resolve_paths(msg, &old_path, &new_path);
+
+ g_dbus_emit_signal(conn, old_path,
+ ADAPTER_INTERFACE, "TrustRemoved",
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+
+ if (new_path) {
+ struct device *device;
+ gboolean trust = FALSE;
+
+ device = adapter_find_device(adapter, address);
+ if (device) {
+ dbus_connection_emit_property_changed(conn,
+ device->path, DEVICE_INTERFACE,
+ "Trusted", DBUS_TYPE_BOOLEAN, &trust);
+ }
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_list_trusts(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ GSList *trusts, *l;
+ char **addrs;
+ bdaddr_t local;
+ int len;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ str2ba(adapter->address, &local);
+
+ trusts = list_trusts(&local, GLOBAL_TRUST);
+
+ addrs = g_new(char *, g_slist_length(trusts));
+
+ for (l = trusts, len = 0; l; l = l->next, len++)
+ addrs[len] = l->data;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &addrs, len,
+ DBUS_TYPE_INVALID);
+
+ g_free(addrs);
+ g_slist_foreach(trusts, (GFunc) g_free, NULL);
+ g_slist_free(trusts);
+
+ return reply;
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *property;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ bdaddr_t ba;
+ char str[249];
+
+ if (check_address(adapter->address) < 0)
+ return adapter_not_ready(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ /* Address */
+ property = adapter->address;
+ dbus_message_iter_append_dict_entry(&dict, "Address",
+ DBUS_TYPE_STRING, &property);
+
+ /* Name */
+ memset(str, 0, sizeof(str));
+ property = str;
+ str2ba(adapter->address, &ba);
+
+ if (!read_local_name(&ba, str))
+ dbus_message_iter_append_dict_entry(&dict, "Name",
+ DBUS_TYPE_STRING, &property);
+
+ /* Mode */
+ property = mode2str(adapter->mode);
+
+ dbus_message_iter_append_dict_entry(&dict, "Mode",
+ DBUS_TYPE_STRING, &property);
+
+ /* DiscoverableTimeout */
+ dbus_message_iter_append_dict_entry(&dict, "DiscoverableTimeout",
+ DBUS_TYPE_UINT32, &adapter->discov_timeout);
+
+ /* PeriodicDiscovery */
+ dbus_message_iter_append_dict_entry(&dict, "PeriodicDiscovery",
+ DBUS_TYPE_BOOLEAN, &adapter->pdiscov_active);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessageIter iter;
+ DBusMessageIter sub;
+ const char *property;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &property);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return invalid_args(msg);
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (g_str_equal("Name", property)) {
+ const char *name;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
+ return invalid_args(msg);
+ dbus_message_iter_get_basic(&sub, &name);
+
+ return set_name(conn, msg, name, data);
+ } else if (g_str_equal("DiscoverableTimeout", property)) {
+ uint32_t timeout;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)
+ return invalid_args(msg);
+ dbus_message_iter_get_basic(&sub, &timeout);
+
+ return set_discoverable_timeout(conn, msg, timeout, data);
+ } else if (g_str_equal("PeriodicDiscovery", 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);
+
+ if (value)
+ return adapter_start_periodic(conn, msg, data);
+ else
+ return adapter_stop_periodic(conn, msg, data);
+ } else if (g_str_equal("Mode", property)) {
+ const char *mode;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
+ return invalid_args(msg);
+
+ dbus_message_iter_get_basic(&sub, &mode);
+
+ adapter->global_mode = str2mode(adapter->address, mode);
+
+ if (adapter->global_mode == adapter->mode)
+ return dbus_message_new_method_return(msg);
+
+ if (adapter->sessions && adapter->global_mode < adapter->mode)
+ return confirm_mode(conn, msg, mode, data);
+
+ return set_mode(conn, msg, str2mode(adapter->address, mode),
+ data);
+ }
+
+ return invalid_args(msg);
+}
+
+static void session_exit(void *data)
+{
+ struct mode_req *req = data;
+ struct adapter *adapter = req->adapter;
+
+ adapter->sessions = g_slist_remove(adapter->sessions, req);
+
+ if (!adapter->sessions) {
+ debug("Falling back to '%s' mode", mode2str(adapter->global_mode));
+ /* FIXME: fallback to previous mode
+ set_mode(req->conn, req->msg, adapter->global_mode, adapter);
+ */
+ }
+ dbus_connection_unref(req->conn);
+ dbus_message_unref(req->msg);
+ g_free(req);
+}
+
+static DBusMessage *request_mode(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *mode;
+ struct adapter *adapter = data;
+ struct mode_req *req;
+ uint8_t new_mode;
+ int ret;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ new_mode = str2mode(adapter->address, mode);
+ if (new_mode != MODE_CONNECTABLE && new_mode != MODE_DISCOVERABLE)
+ return invalid_args(msg);
+
+ if (!adapter->agent)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "No agent registered");
+
+ if (g_slist_find_custom(adapter->sessions, msg,
+ (GCompareFunc) find_session))
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Mode already requested");
+
+ req = g_new0(struct mode_req, 1);
+ req->adapter = adapter;
+ req->conn = dbus_connection_ref(conn);
+ req->msg = dbus_message_ref(msg);
+ req->mode = new_mode;
+ req->id = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ session_exit, req, NULL);
+
+ if (!adapter->sessions)
+ adapter->global_mode = adapter->mode;
+ adapter->sessions = g_slist_append(adapter->sessions, req);
+
+ /* No need to change mode */
+ if (adapter->mode >= new_mode)
+ return dbus_message_new_method_return(msg);
+
+ ret = agent_confirm_mode_change(adapter->agent, mode, confirm_mode_cb,
+ req);
+ if (ret < 0) {
+ dbus_message_unref(req->msg);
+ g_dbus_remove_watch(req->conn, req->id);
+ dbus_connection_unref(req->conn);
+ g_free(req);
+ return invalid_args(msg);
+ }
+
+ return NULL;
+}
+
+static DBusMessage *release_mode(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ GSList *l;
+
+ l = g_slist_find_custom(adapter->sessions, msg,
+ (GCompareFunc) find_session);
+ if (!l)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "No Mode to release");
+
+ session_exit(l->data);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *list_devices(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ GSList *l;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+
+ for (l = adapter->devices; l; l = l->next) {
+ struct device *device = l->data;
+
+ if (device->temporary)
+ continue;
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_OBJECT_PATH, &device->path);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static DBusMessage *create_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ struct device *device;
+ const gchar *address;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID) == FALSE)
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ if (adapter_find_device(adapter, address))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".AlreadyExists",
+ "Device already exists");
+
+ debug("create_device(%s)", address);
+
+ device = device_create(conn, adapter, address);
+ if (!device)
+ return NULL;
+
+ device->temporary = FALSE;
+
+ device_browse(device, conn, msg, NULL);
+
+ adapter->devices = g_slist_append(adapter->devices, device);
+
+ return NULL;
+}
+
+static uint8_t parse_io_capability(const char *capability)
+{
+ if (g_str_equal(capability, ""))
+ return IO_CAPABILITY_DISPLAYYESNO;
+ if (g_str_equal(capability, "DisplayOnly"))
+ return IO_CAPABILITY_DISPLAYONLY;
+ if (g_str_equal(capability, "DisplayYesNo"))
+ return IO_CAPABILITY_DISPLAYYESNO;
+ if (g_str_equal(capability, "KeyboardOnly"))
+ return IO_CAPABILITY_KEYBOARDONLY;
+ if (g_str_equal(capability, "NoInputOutput"))
+ return IO_CAPABILITY_NOINPUTOUTPUT;
+ return IO_CAPABILITY_INVALID;
+}
+
+static DBusMessage *create_paired_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const gchar *address, *agent_path, *capability;
+ uint8_t cap;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_STRING, &capability,
+ DBUS_TYPE_INVALID) == FALSE)
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ cap = parse_io_capability(capability);
+ if (cap == IO_CAPABILITY_INVALID)
+ return invalid_args(msg);
+
+ return create_bonding(conn, msg, address, agent_path, cap, data);
+}
+
+static gint device_path_cmp(struct device *device, const gchar *path)
+{
+ return strcasecmp(device->path, path);
+}
+
+static DBusMessage *remove_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ struct device *device;
+ const char *path;
+ GSList *l;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE)
+ return invalid_args(msg);
+
+ l = g_slist_find_custom(adapter->devices,
+ path, (GCompareFunc) device_path_cmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Device does not exist");
+ device = l->data;
+
+ if (device->temporary || device->discov_active)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Device creation in progress");
+
+ adapter_remove_device(conn, adapter, device);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *find_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ struct device *device;
+ DBusMessage *reply;
+ const gchar *address;
+ GSList *l;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ l = g_slist_find_custom(adapter->devices,
+ address, (GCompareFunc) device_address_cmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Device does not exist");
+
+ device = l->data;
+
+ if (device->temporary)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Device creation in progress");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_OBJECT_PATH, &device->path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static void agent_removed(struct agent *agent, struct adapter *adapter)
+{
+ struct pending_auth_info *auth;
+ GSList *l;
+
+ adapter->agent = NULL;
+
+ l = g_slist_find_custom(adapter->auth_reqs, agent,
+ auth_info_agent_cmp);
+ if (!l)
+ return;
+
+ auth = l->data;
+ auth->agent = NULL;
+}
+
+static DBusMessage *register_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path, *name, *capability;
+ struct agent *agent;
+ struct adapter *adapter = data;
+ uint8_t cap;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (adapter->agent)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".AlreadyExists",
+ "Agent already exists");
+
+ cap = parse_io_capability(capability);
+ if (cap == IO_CAPABILITY_INVALID)
+ return invalid_args(msg);
+
+ name = dbus_message_get_sender(msg);
+
+ agent = agent_create(adapter, name, path, cap,
+ (agent_remove_cb) agent_removed, adapter);
+ if (!agent)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ "Failed to create a new agent");
+
+ adapter->agent = agent;
+
+ debug("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)
+{
+ const char *path, *name;
+ struct adapter *adapter = data;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ name = dbus_message_get_sender(msg);
+
+ if (!adapter->agent || !agent_matches(adapter->agent, name, path))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "No such agent");
+
+ agent_destroy(adapter->agent, FALSE);
+ adapter->agent = NULL;
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *add_service_record(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ const char *sender, *record;
+ dbus_uint32_t handle;
+ bdaddr_t src;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ sender = dbus_message_get_sender(msg);
+ str2ba(adapter->address, &src);
+ err = add_xml_record(conn, sender, &src, record, &handle);
+ if (err < 0)
+ return failed_strerror(msg, err);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *update_service_record(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ bdaddr_t src;
+
+ str2ba(adapter->address, &src);
+
+ return update_xml_record(conn, msg, &src);
+}
+
+static DBusMessage *remove_service_record(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ dbus_uint32_t handle;
+ const char *sender;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ sender = dbus_message_get_sender(msg);
+
+ if (remove_record(conn, sender, handle) < 0)
+ return not_available(msg);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *request_authorization(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ /* FIXME implement the request */
+
+ return NULL;
+}
+
+static DBusMessage *cancel_authorization(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ /* FIXME implement cancel request */
+
+ return dbus_message_new_method_return(msg);
+}
+
+/* BlueZ 4.0 API */
+static GDBusMethodTable adapter_methods[] = {
+ { "GetProperties", "", "a{sv}",get_properties },
+ { "SetProperty", "sv", "", set_property,
+ G_DBUS_METHOD_FLAG_ASYNC},
+ { "RequestMode", "s", "", request_mode,
+ G_DBUS_METHOD_FLAG_ASYNC},
+ { "ReleaseMode", "", "", release_mode },
+ { "DiscoverDevices", "", "", adapter_discover_devices},
+ { "CancelDiscovery", "", "", adapter_cancel_discovery,
+ G_DBUS_METHOD_FLAG_ASYNC},
+ { "ListDevices", "", "ao", list_devices },
+ { "CreateDevice", "s", "o", create_device,
+ G_DBUS_METHOD_FLAG_ASYNC},
+ { "CreatePairedDevice", "sos", "o", create_paired_device,
+ G_DBUS_METHOD_FLAG_ASYNC},
+ { "RemoveDevice", "o", "", remove_device },
+ { "FindDevice", "s", "o", find_device },
+ { "RegisterAgent", "os", "", register_agent },
+ { "UnregisterAgent", "o", "", unregister_agent },
+ { "AddServiceRecord", "s", "u", add_service_record },
+ { "UpdateServiceRecord","us", "", update_service_record },
+ { "RemoveServiceRecord","u", "", remove_service_record },
+ { "RequestAuthorization","su", "", request_authorization,
+ G_DBUS_METHOD_FLAG_ASYNC},
+ { "CancelAuthorization","", "", cancel_authorization },
+ { }
+};
+
+/* Deprecated */
+static GDBusMethodTable old_adapter_methods[] = {
+ { "GetInfo", "", "a{sv}",
+ adapter_get_info },
+ { "GetAddress", "", "s",
+ adapter_get_address },
+ { "GetVersion", "", "s",
+ adapter_get_version },
+ { "GetRevision", "", "s",
+ adapter_get_revision },
+ { "GetManufacturer", "", "s",
+ adapter_get_manufacturer },
+ { "GetCompany", "", "s",
+ adapter_get_company },
+ { "ListAvailableModes", "", "as",
+ adapter_list_modes },
+ { "GetMode", "", "s",
+ adapter_get_mode },
+ { "SetMode", "s", "",
+ adapter_set_mode },
+ { "GetDiscoverableTimeout", "", "u",
+ adapter_get_discoverable_to },
+ { "SetDiscoverableTimeout", "u", "",
+ adapter_set_discoverable_to },
+ { "IsConnectable", "", "b",
+ adapter_is_connectable },
+ { "IsDiscoverable", "", "b",
+ adapter_is_discoverable },
+ { "IsConnected", "s", "b",
+ adapter_is_connected },
+ { "ListConnections", "", "as",
+ adapter_list_connections },
+ { "GetMajorClass", "", "s",
+ adapter_get_major_class },
+ { "ListAvailableMinorClasses", "", "as",
+ adapter_list_minor_classes },
+ { "GetMinorClass", "", "s",
+ adapter_get_minor_class },
+ { "SetMinorClass", "s", "",
+ adapter_set_minor_class },
+ { "GetServiceClasses", "", "as",
+ adapter_get_service_classes },
+ { "GetName", "", "s",
+ adapter_get_name },
+ { "SetName", "s", "",
+ adapter_set_name },
+
+ { "GetRemoteInfo", "s", "a{sv}",
+ adapter_get_remote_info },
+ { "GetRemoteServiceRecord", "su", "ay",
+ adapter_get_remote_svc, G_DBUS_METHOD_FLAG_ASYNC },
+ { "GetRemoteServiceRecordAsXML", "su", "s",
+ adapter_get_remote_svc_xml, G_DBUS_METHOD_FLAG_ASYNC },
+ { "GetRemoteServiceHandles", "ss", "au",
+ adapter_get_remote_svc_handles, G_DBUS_METHOD_FLAG_ASYNC },
+ { "GetRemoteServiceIdentifiers", "s", "as",
+ adapter_get_remote_svc_identifiers, G_DBUS_METHOD_FLAG_ASYNC },
+ { "FinishRemoteServiceTransaction", "s", "",
+ adapter_finish_sdp_transact },
+ { "GetRemoteVersion", "s", "s",
+ adapter_get_remote_version },
+ { "GetRemoteRevision", "s", "s",
+ adapter_get_remote_revision },
+ { "GetRemoteManufacturer", "s", "s",
+ adapter_get_remote_manufacturer },
+ { "GetRemoteCompany", "s", "s",
+ adapter_get_remote_company },
+ { "GetRemoteMajorClass", "s", "s",
+ adapter_get_remote_major_class },
+ { "GetRemoteMinorClass", "s", "s",
+ adapter_get_remote_minor_class },
+ { "GetRemoteServiceClasses", "s", "as",
+ adapter_get_remote_service_cls },
+ { "GetRemoteClass", "s", "u",
+ adapter_get_remote_class },
+ { "GetRemoteFeatures", "s", "ay",
+ adapter_get_remote_features },
+ { "GetRemoteName", "s", "s",
+ adapter_get_remote_name },
+ { "GetRemoteAlias", "s", "s",
+ adapter_get_remote_alias },
+ { "SetRemoteAlias", "ss", "",
+ adapter_set_remote_alias },
+ { "ClearRemoteAlias", "s", "",
+ adapter_clear_remote_alias },
+
+ { "LastSeen", "s", "s",
+ adapter_last_seen },
+ { "LastUsed", "s", "s",
+ adapter_last_used },
+
+ { "DisconnectRemoteDevice", "s", "",
+ adapter_dc_remote_device, G_DBUS_METHOD_FLAG_ASYNC},
+
+ { "CreateBonding", "s", "",
+ adapter_create_bonding, G_DBUS_METHOD_FLAG_ASYNC},
+ { "CancelBondingProcess", "s", "",
+ adapter_cancel_bonding },
+ { "RemoveBonding", "s", "",
+ adapter_remove_bonding },
+ { "HasBonding", "s", "b",
+ adapter_has_bonding },
+ { "ListBondings", "", "as",
+ adapter_list_bondings },
+ { "GetPinCodeLength", "s", "y",
+ adapter_get_pin_code_length },
+ { "GetEncryptionKeySize", "s", "y",
+ adapter_get_encryption_key_size },
+
+ { "StartPeriodicDiscovery", "", "",
+ adapter_start_periodic },
+ { "StopPeriodicDiscovery", "", "",
+ adapter_stop_periodic },
+ { "IsPeriodicDiscovery", "", "b",
+ adapter_is_periodic },
+ { "SetPeriodicDiscoveryNameResolving", "b", "",
+ adapter_set_pdiscov_resolve },
+ { "GetPeriodicDiscoveryNameResolving", "", "b",
+ adapter_get_pdiscov_resolve },
+ { "DiscoverDevices", "", "",
+ adapter_discover_devices },
+ { "CancelDiscovery", "", "",
+ adapter_cancel_discovery, G_DBUS_METHOD_FLAG_ASYNC },
+ { "DiscoverDevicesWithoutNameResolving","", "",
+ adapter_discover_devices },
+ { "ListRemoteDevices", "", "as",
+ adapter_list_remote_devices },
+ { "ListRecentRemoteDevices", "s", "as",
+ adapter_list_recent_remote_devices},
+
+ { "SetTrusted", "s", "",
+ adapter_set_trusted },
+ { "IsTrusted", "s", "b",
+ adapter_is_trusted },
+ { "RemoveTrust", "s", "",
+ adapter_remove_trust },
+ { "ListTrusts", "", "as",
+ adapter_list_trusts },
+
+ { }
+};
+
+/* BlueZ 4.X */
+static GDBusSignalTable adapter_signals[] = {
+ { "DiscoveryStarted", "" },
+ { "DiscoveryCompleted", "" },
+ { "DeviceCreated", "o" },
+ { "DeviceRemoved", "o" },
+ { "DeviceFound", "sa{sv}" },
+ { "PropertyChanged", "sv" },
+ { "DeviceDisappeared", "s" },
+ { }
+};
+
+/* Deprecated */
+static GDBusSignalTable old_adapter_signals[] = {
+ { "DiscoveryStarted", "" },
+ { "DiscoveryCompleted", "" },
+ { "ModeChanged", "s" },
+ { "DiscoverableTimeoutChanged", "u" },
+ { "MinorClassChanged", "s" },
+ { "NameChanged", "s" },
+ { "PeriodicDiscoveryStarted", "" },
+ { "PeriodicDiscoveryStopped", "" },
+ { "RemoteDeviceFound", "sun" },
+ { "RemoteDeviceDisappeared", "s" },
+ { "RemoteClassUpdated", "su" },
+ { "RemoteNameUpdated", "ss" },
+ { "RemoteNameFailed", "s" },
+ { "RemoteNameRequested", "s" },
+ { "RemoteAliasChanged", "ss" },
+ { "RemoteAliasCleared", "s" },
+ { "RemoteDeviceConnected", "s" },
+ { "RemoteDeviceDisconnectRequested", "s" },
+ { "RemoteDeviceDisconnected", "s" },
+ { "RemoteIdentifiersUpdated", "sas" },
+ { "BondingCreated", "s" },
+ { "BondingRemoved", "s" },
+ { "TrustAdded", "s" },
+ { "TrustRemoved", "s" },
+ { }
+};
+
+dbus_bool_t adapter_init(DBusConnection *conn,
+ const char *path, struct adapter *adapter)
+{
+ if (hcid_dbus_use_experimental())
+ g_dbus_register_interface(conn, path + ADAPTER_PATH_INDEX,
+ ADAPTER_INTERFACE, adapter_methods,
+ adapter_signals, NULL, adapter, NULL);
+
+ return g_dbus_register_interface(conn,
+ path, ADAPTER_INTERFACE,
+ old_adapter_methods, old_adapter_signals,
+ NULL, adapter, NULL);
+}
+
+dbus_bool_t adapter_cleanup(DBusConnection *conn, const char *path)
+{
+ return g_dbus_unregister_interface(conn, path, ADAPTER_INTERFACE);
+}
+
+const char *major_class_str(uint32_t class)
+{
+ uint8_t index = (class >> 8) & 0x1F;
+
+ if (index > 8)
+ return major_cls[9]; /* uncategorized */
+
+ return major_cls[index];
+}
+
+const char *minor_class_str(uint32_t class)
+{
+ uint8_t major_index = (class >> 8) & 0x1F;
+ uint8_t minor_index;
+
+ switch (major_index) {
+ case 1: /* computer */
+ minor_index = (class >> 2) & 0x3F;
+ if (minor_index < NUM_ELEMENTS(computer_minor_cls))
+ return computer_minor_cls[minor_index];
+ else
+ return "";
+ case 2: /* phone */
+ minor_index = (class >> 2) & 0x3F;
+ if (minor_index < NUM_ELEMENTS(phone_minor_cls))
+ return phone_minor_cls[minor_index];
+ return "";
+ case 3: /* access point */
+ minor_index = (class >> 5) & 0x07;
+ if (minor_index < NUM_ELEMENTS(access_point_minor_cls))
+ return access_point_minor_cls[minor_index];
+ else
+ return "";
+ case 4: /* audio/video */
+ minor_index = (class >> 2) & 0x3F;
+ if (minor_index < NUM_ELEMENTS(audio_video_minor_cls))
+ return audio_video_minor_cls[minor_index];
+ else
+ return "";
+ case 5: /* peripheral */
+ minor_index = (class >> 6) & 0x03;
+ if (minor_index < NUM_ELEMENTS(peripheral_minor_cls))
+ return peripheral_minor_cls[minor_index];
+ else
+ return "";
+ case 6: /* imaging */
+ {
+ uint8_t shift_minor = 0;
+
+ minor_index = (class >> 4) & 0x0F;
+ while (shift_minor < (sizeof(imaging_minor_cls) / sizeof(*imaging_minor_cls))) {
+ if (((minor_index >> shift_minor) & 0x01) == 0x01)
+ return imaging_minor_cls[shift_minor];
+ shift_minor++;
+ }
+ }
+ break;
+ case 7: /* wearable */
+ minor_index = (class >> 2) & 0x3F;
+ if (minor_index < NUM_ELEMENTS(wearable_minor_cls))
+ return wearable_minor_cls[minor_index];
+ else
+ return "";
+ case 8: /* toy */
+ minor_index = (class >> 2) & 0x3F;
+ if (minor_index < NUM_ELEMENTS(toy_minor_cls))
+ return toy_minor_cls[minor_index];
+ else
+ return "";
+ }
+
+ return "";
+}
+
+GSList *service_classes_str(uint32_t class)
+{
+ uint8_t services = class >> 16;
+ GSList *l = NULL;
+ int i;
+
+ for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) {
+ if (!(services & (1 << i)))
+ continue;
+
+ l = g_slist_append(l, (void *) service_cls[i]);
+ }
+
+ return l;
+}
diff --git a/utils/hcid/adapter.h b/utils/hcid/adapter.h
new file mode 100644
index 00000000..f6ed7a22
--- /dev/null
+++ b/utils/hcid/adapter.h
@@ -0,0 +1,165 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define ADAPTER_INTERFACE "org.bluez.Adapter"
+
+#define INVALID_DEV_ID 0xFFFF
+
+#define BONDING_TIMEOUT 45000 /* 45 sec */
+
+#define DC_PENDING_TIMEOUT 2000 /* 2 secs */
+
+/* Discover types */
+#define DISCOVER_TYPE_NONE 0x00
+#define STD_INQUIRY 0x01
+#define PERIODIC_INQUIRY 0x02
+
+/* Actions executed after inquiry complete */
+#define RESOLVE_NAME 0x10
+
+typedef enum {
+ NAME_ANY,
+ NAME_NOT_REQUIRED, /* used by get remote name without name resolving */
+ NAME_REQUIRED, /* remote name needs be resolved */
+ NAME_REQUESTED, /* HCI remote name request was sent */
+ NAME_SENT /* D-Bus signal RemoteNameUpdated sent */
+} name_status_t;
+
+typedef enum {
+ AUTH_TYPE_PINCODE,
+ AUTH_TYPE_PASSKEY,
+ AUTH_TYPE_CONFIRM,
+ AUTH_TYPE_NOTIFY,
+} auth_type_t;
+
+struct remote_dev_info {
+ bdaddr_t bdaddr;
+ int8_t rssi;
+ name_status_t name_status;
+};
+
+struct bonding_request_info {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ struct adapter *adapter;
+ bdaddr_t bdaddr;
+ GIOChannel *io;
+ guint io_id;
+ guint listener_id;
+ int hci_status;
+ int cancel;
+ int auth_active;
+};
+
+struct pending_auth_info {
+ auth_type_t type;
+ bdaddr_t bdaddr;
+ gboolean replied; /* If we've already replied to the request */
+ struct agent *agent; /* Agent associated with the request */
+};
+
+struct active_conn_info {
+ bdaddr_t bdaddr;
+ uint16_t handle;
+};
+
+struct pending_dc_info {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ uint16_t conn_handle;
+ guint timeout_id;
+};
+
+struct adapter {
+ uint16_t dev_id;
+ int up;
+ char *path; /* adapter object path */
+ char address[18]; /* adapter Bluetooth Address */
+ guint timeout_id; /* discoverable timeout id */
+ uint32_t discov_timeout; /* discoverable time(msec) */
+ uint8_t scan_enable; /* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */
+ uint8_t mode; /* off, connectable, discoverable, limited */
+ uint8_t global_mode; /* last valid global mode */
+ uint8_t class[3]; /* device class */
+ int discov_active; /* standard discovery active: includes name resolution step */
+ int pdiscov_active; /* periodic discovery active */
+ int pinq_idle; /* tracks the idle time for periodic inquiry */
+ int discov_type; /* type requested */
+ int pdiscov_resolve_names; /* Resolve names when doing periodic discovery */
+ GSList *found_devices;
+ GSList *oor_devices; /* out of range device list */
+ char *pdiscov_requestor; /* periodic discovery requestor unique name */
+ guint pdiscov_listener;
+ char *discov_requestor; /* discovery requestor unique name */
+ guint discov_listener;
+ DBusMessage *discovery_cancel; /* discovery cancel message request */
+ GSList *passkey_agents;
+ struct agent *agent; /* For the new API */
+ GSList *active_conn;
+ struct bonding_request_info *bonding;
+ GSList *auth_reqs; /* Received and replied HCI
+ authentication requests */
+ struct pending_dc_info *pending_dc;
+ GSList *devices; /* Devices structure pointers */
+ GSList *sessions; /* Request Mode sessions */
+};
+
+dbus_bool_t adapter_init(DBusConnection *conn,
+ const char *path, struct adapter *adapter);
+
+dbus_bool_t adapter_cleanup(DBusConnection *conn, const char *path);
+
+struct device *adapter_get_device(DBusConnection *conn,
+ struct adapter *adapter, const gchar *address);
+
+struct device *adapter_find_device(struct adapter *adapter, const char *dest);
+
+void adapter_remove_device(DBusConnection *conn, struct adapter *adapter,
+ struct device *device);
+struct device *adapter_create_device(DBusConnection *conn,
+ struct adapter *adapter, const char *address);
+
+const char *major_class_str(uint32_t class);
+
+const char *minor_class_str(uint32_t class);
+
+const char *mode2str(uint8_t mode);
+
+uint8_t str2mode(const char *addr, const char *mode);
+
+GSList *service_classes_str(uint32_t class);
+
+int pending_remote_name_cancel(struct adapter *adapter);
+
+void dc_pending_timeout_cleanup(struct adapter *adapter);
+
+void remove_pending_device(struct adapter *adapter);
+
+void adapter_auth_request_replied(struct adapter *adapter, bdaddr_t *dba);
+struct pending_auth_info *adapter_find_auth_request(struct adapter *adapter,
+ bdaddr_t *dba);
+void adapter_remove_auth_request(struct adapter *adapter, bdaddr_t *dba);
+struct pending_auth_info *adapter_new_auth_request(struct adapter *adapter,
+ bdaddr_t *dba,
+ auth_type_t type);
diff --git a/utils/hcid/agent.c b/utils/hcid/agent.c
new file mode 100644
index 00000000..91dbd2d9
--- /dev/null
+++ b/utils/hcid/agent.c
@@ -0,0 +1,730 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Copyright (C) 2004-2008 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 <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "dbus-common.h"
+#include "dbus-service.h"
+#include "dbus-error.h"
+#include "error.h"
+#include "adapter.h"
+#include "dbus-hci.h"
+#include "device.h"
+#include "agent.h"
+
+#define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */
+#define AGENT_TIMEOUT (10 * 60 * 1000) /* 10 minutes */
+
+typedef enum {
+ AGENT_REQUEST_PASSKEY,
+ AGENT_REQUEST_CONFIRMATION,
+ AGENT_REQUEST_PINCODE,
+ AGENT_REQUEST_AUTHORIZE,
+ AGENT_REQUEST_CONFIRM_MODE
+} agent_request_type_t;
+
+struct agent {
+ struct adapter *adapter;
+ char *name;
+ char *path;
+ uint8_t capability;
+ struct agent_request *request;
+ int exited;
+ agent_remove_cb remove_cb;
+ void *remove_cb_data;
+ guint listener_id;
+};
+
+struct agent_request {
+ agent_request_type_t type;
+ struct agent *agent;
+ DBusPendingCall *call;
+ void *cb;
+ void *user_data;
+};
+
+static DBusConnection *connection = NULL;
+
+static void agent_release(struct agent *agent)
+{
+ DBusMessage *message;
+
+ debug("Releasing agent %s, %s", agent->name, agent->path);
+
+ if (agent->request)
+ agent_cancel(agent);
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "Release");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(connection, message, NULL);
+
+ dbus_message_unref(message);
+}
+
+static int send_cancel_request(struct agent_request *req)
+{
+ DBusMessage *message;
+
+ message = dbus_message_new_method_call(req->agent->name, req->agent->path,
+ "org.bluez.Agent", "Cancel");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return -ENOMEM;
+ }
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(connection, message, NULL);
+
+ dbus_message_unref(message);
+
+ return 0;
+}
+
+static void agent_request_free(struct agent_request *req)
+{
+ if (req->call)
+ dbus_pending_call_unref(req->call);
+ if (req->agent && req->agent->request)
+ req->agent->request = NULL;
+ g_free(req);
+}
+
+static void agent_exited(void *user_data)
+{
+ struct agent *agent = user_data;
+
+ debug("Agent exited without calling Unregister");
+
+ agent_destroy(agent, TRUE);
+}
+
+static void agent_free(struct agent *agent)
+{
+ if (!agent)
+ return;
+
+ if (agent->remove_cb)
+ agent->remove_cb(agent, agent->remove_cb_data);
+
+ if (agent->request) {
+ DBusError err;
+ agent_pincode_cb pincode_cb;
+ agent_cb cb;
+
+ dbus_error_init(&err);
+ dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled");
+
+ switch (agent->request->type) {
+ case AGENT_REQUEST_PINCODE:
+ pincode_cb = agent->request->cb;
+ pincode_cb(agent, &err, NULL, agent->request->user_data);
+ break;
+ default:
+ cb = agent->request->cb;
+ cb(agent, &err, agent->request->user_data);
+ }
+
+ dbus_error_free(&err);
+
+ agent_cancel(agent);
+ }
+
+ if (!agent->exited) {
+ g_dbus_remove_watch(connection, agent->listener_id);
+ agent_release(agent);
+ }
+
+ g_free(agent->name);
+ g_free(agent->path);
+
+ g_free(agent);
+}
+
+struct agent *agent_create(struct adapter *adapter, const char *name,
+ const char *path, uint8_t capability,
+ agent_remove_cb cb, void *remove_cb_data)
+{
+ struct agent *agent;
+
+ if (adapter->agent && g_str_equal(adapter->agent->name, name))
+ return NULL;
+
+ agent = g_new0(struct agent, 1);
+
+ agent->adapter = adapter;
+ agent->name = g_strdup(name);
+ agent->path = g_strdup(path);
+ agent->capability = capability;
+ agent->remove_cb = cb;
+ agent->remove_cb_data = remove_cb_data;
+
+ agent->listener_id = g_dbus_add_disconnect_watch(connection, name,
+ agent_exited, agent,
+ NULL);
+
+ return agent;
+}
+
+int agent_destroy(struct agent *agent, gboolean exited)
+{
+ 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,
+ void *user_data)
+{
+ struct agent_request *req;
+
+ req = g_new0(struct agent_request, 1);
+
+ req->agent = agent;
+ req->type = type;
+ req->cb = cb;
+ req->user_data = user_data;
+
+ return req;
+}
+
+int agent_cancel(struct agent *agent)
+{
+ if (!agent->request)
+ return -EINVAL;
+
+ if (agent->request->call)
+ dbus_pending_call_cancel(agent->request->call);
+
+ if (!agent->exited)
+ send_cancel_request(agent->request);
+
+ agent_request_free(agent->request);
+ agent->request = NULL;
+
+ return 0;
+}
+
+static DBusPendingCall *agent_call_authorize(struct agent *agent,
+ const char *device_path,
+ const char *uuid)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "Authorize");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+ return call;
+}
+
+static void simple_agent_reply(DBusPendingCall *call, void *user_data)
+{
+ struct agent_request *req = user_data;
+ struct agent *agent = req->agent;
+ DBusMessage *message;
+ DBusError err;
+ agent_cb cb = req->cb;
+
+ /* steal_reply will always return non-NULL since the callback
+ * is only called after a reply has been received */
+ message = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+
+ error("Agent replied with an error: %s, %s",
+ err.name, err.message);
+
+ cb(agent, &err, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
+ error("Wrong reply signature: %s", err.message);
+ cb(agent, &err, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ cb(agent, NULL, req->user_data);
+done:
+ dbus_message_unref(message);
+
+ agent->request = NULL;
+ agent_request_free(req);
+}
+
+int agent_authorize(struct agent *agent,
+ const char *path,
+ const char *uuid,
+ agent_cb cb,
+ void *user_data)
+{
+ struct agent_request *req;
+
+ if (agent->request)
+ return -EBUSY;
+
+ req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb, user_data);
+
+ req->call = agent_call_authorize(agent, path, uuid);
+ if (!req->call) {
+ agent_request_free(req);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+ agent->request = req;
+
+ debug("authorize request was sent for %s", path);
+
+ return 0;
+}
+
+static DBusPendingCall *pincode_request_new(struct agent *agent,
+ const char *device_path,
+ dbus_bool_t numeric)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "RequestPinCode");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+ return call;
+}
+
+static void pincode_reply(DBusPendingCall *call, void *user_data)
+{
+ struct agent_request *req = user_data;
+ struct agent *agent = req->agent;
+ struct adapter *adapter = agent->adapter;
+ agent_pincode_cb cb = req->cb;
+ DBusMessage *message;
+ DBusError err;
+ bdaddr_t sba;
+ size_t len;
+ char *pin;
+
+ /* steal_reply will always return non-NULL since the callback
+ * is only called after a reply has been received */
+ message = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+ error("Agent replied with an error: %s, %s",
+ err.name, err.message);
+
+ cb(agent, &err, NULL, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(message, &err,
+ DBUS_TYPE_STRING, &pin,
+ DBUS_TYPE_INVALID)) {
+ error("Wrong passkey reply signature: %s", err.message);
+ cb(agent, &err, NULL, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ len = strlen(pin);
+
+ dbus_error_init(&err);
+ if (len > 16 || len < 1) {
+ error("Invalid passkey length from handler");
+ dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs",
+ "Invalid passkey length");
+ cb(agent, &err, NULL, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ str2ba(adapter->address, &sba);
+
+ set_pin_length(&sba, len);
+
+ cb(agent, NULL, pin, req->user_data);
+
+done:
+ if (message)
+ dbus_message_unref(message);
+
+ dbus_pending_call_cancel(req->call);
+ agent_request_free(req);
+}
+
+int agent_request_pincode(struct agent *agent, struct device *device,
+ agent_pincode_cb cb, void *user_data)
+{
+ struct agent_request *req;
+
+ if (agent->request)
+ return -EBUSY;
+
+ req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb, user_data);
+
+ req->call = pincode_request_new(agent, device->path, FALSE);
+ if (!req->call)
+ goto failed;
+
+ dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL);
+
+ agent->request = req;
+
+ return 0;
+
+failed:
+ g_free(req);
+ return -1;
+}
+
+static DBusPendingCall *confirm_mode_change_request_new(struct agent *agent,
+ const char *mode)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "ConfirmModeChange");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+
+ return call;
+}
+
+int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
+ agent_cb cb, void *user_data)
+{
+ struct agent_request *req;
+
+ if (agent->request)
+ return -EBUSY;
+
+ debug("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s",
+ agent->name, agent->path, new_mode);
+
+ req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE,
+ cb, user_data);
+
+ req->call = confirm_mode_change_request_new(agent, new_mode);
+ if (!req->call)
+ goto failed;
+
+ dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+
+ agent->request = req;
+
+ return 0;
+
+failed:
+ agent_request_free(req);
+ return -1;
+}
+
+static DBusPendingCall *passkey_request_new(struct agent *agent,
+ const char *device_path)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "RequestPasskey");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+ return call;
+}
+
+static void passkey_reply(DBusPendingCall *call, void *user_data)
+{
+ struct agent_request *req = user_data;
+ struct agent *agent = req->agent;
+ agent_passkey_cb cb = req->cb;
+ DBusMessage *message;
+ DBusError err;
+ uint32_t passkey;
+
+ /* steal_reply will always return non-NULL since the callback
+ * is only called after a reply has been received */
+ message = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+ error("Agent replied with an error: %s, %s",
+ err.name, err.message);
+ cb(agent, &err, 0, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(message, &err,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID)) {
+ error("Wrong passkey reply signature: %s", err.message);
+ cb(agent, &err, 0, req->user_data);
+ dbus_error_free(&err);
+ goto done;
+ }
+
+ cb(agent, NULL, passkey, req->user_data);
+
+done:
+ if (message)
+ dbus_message_unref(message);
+
+ dbus_pending_call_cancel(req->call);
+ agent_request_free(req);
+}
+
+int agent_request_passkey(struct agent *agent, struct device *device,
+ agent_passkey_cb cb, void *user_data)
+{
+ struct agent_request *req;
+
+ if (agent->request)
+ return -EBUSY;
+
+ debug("Calling Agent.RequestPasskey: name=%s, path=%s",
+ agent->name, agent->path);
+
+ req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb, user_data);
+
+ req->call = passkey_request_new(agent, device->path);
+ if (!req->call)
+ goto failed;
+
+ dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL);
+
+ agent->request = req;
+
+ return 0;
+
+failed:
+ agent_request_free(req);
+ return -1;
+}
+
+static DBusPendingCall *confirmation_request_new(struct agent *agent,
+ const char *device_path,
+ uint32_t passkey)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "RequestConfirmation");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_OBJECT_PATH, &device_path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+
+ return call;
+}
+
+int agent_request_confirmation(struct agent *agent, struct device *device,
+ uint32_t passkey, agent_cb cb,
+ void *user_data)
+{
+ struct agent_request *req;
+
+ if (agent->request)
+ return -EBUSY;
+
+ debug("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
+ agent->name, agent->path, passkey);
+
+ req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
+ user_data);
+
+ req->call = confirmation_request_new(agent, device->path, passkey);
+ if (!req->call)
+ goto failed;
+
+ dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+
+ agent->request = req;
+
+ return 0;
+
+failed:
+ agent_request_free(req);
+ return -1;
+}
+
+int agent_display_passkey(struct agent *agent, struct device *device,
+ uint32_t passkey)
+{
+ DBusMessage *message;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.Agent", "DisplayPasskey");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return -1;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_OBJECT_PATH, &device->path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID);
+
+ if (!g_dbus_send_message(connection, message)) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return -1;
+ }
+
+ return 0;
+}
+
+uint8_t agent_get_io_capability(struct agent *agent)
+{
+ return agent->capability;
+}
+
+gboolean agent_matches(struct agent *agent, const char *name, const char *path)
+{
+ if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path))
+ return TRUE;
+
+ return FALSE;
+}
+
+void agent_exit(void)
+{
+ dbus_connection_unref(connection);
+}
+
+void agent_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+}
diff --git a/utils/hcid/agent.h b/utils/hcid/agent.h
new file mode 100644
index 00000000..37ee5edd
--- /dev/null
+++ b/utils/hcid/agent.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct agent;
+
+typedef void (*agent_cb) (struct agent *agent, DBusError *err,
+ void *user_data);
+
+typedef void (*agent_pincode_cb) (struct agent *agent, DBusError *err,
+ const char *pincode, void *user_data);
+
+typedef void (*agent_passkey_cb) (struct agent *agent, DBusError *err,
+ uint32_t passkey, void *user_data);
+
+typedef void (*agent_remove_cb) (struct agent *agent, void *user_data);
+
+struct agent *agent_create(struct adapter *adapter, const char *name,
+ const char *path, uint8_t capability,
+ agent_remove_cb cb, void *remove_cb_data);
+
+int agent_destroy(struct agent *agent, gboolean exited);
+
+int agent_authorize(struct agent *agent, const char *path,
+ const char *uuid, agent_cb cb, void *user_data);
+
+int agent_request_pincode(struct agent *agent, struct device *device,
+ agent_pincode_cb cb, void *user_data);
+
+int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
+ agent_cb cb, void *user_data);
+
+int agent_request_passkey(struct agent *agent, struct device *device,
+ agent_passkey_cb cb, void *user_data);
+
+int agent_request_confirmation(struct agent *agent, struct device *device,
+ uint32_t passkey, agent_cb cb,
+ void *user_data);
+
+int agent_display_passkey(struct agent *agent, struct device *device,
+ uint32_t passkey);
+
+int agent_cancel(struct agent *agent);
+
+uint8_t agent_get_io_capability(struct agent *agent);
+
+gboolean agent_matches(struct agent *agent, const char *name, const char *path);
+
+void agent_init(void);
+void agent_exit(void);
+
diff --git a/utils/hcid/bluetooth.conf b/utils/hcid/bluetooth.conf
new file mode 100644
index 00000000..88545fac
--- /dev/null
+++ b/utils/hcid/bluetooth.conf
@@ -0,0 +1,37 @@
+<!-- This configuration file specifies the required security policies
+ for Bluetooth core daemon to work. -->
+
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- ../system.conf have denied everything, so we just punch some holes -->
+
+ <policy user="root">
+ <allow own="org.bluez"/>
+ </policy>
+
+ <policy at_console="true">
+ <allow send_path="/"/>
+ <allow send_path="/org/bluez"/>
+
+ <allow send_destination="org.bluez.Manager"/>
+ <allow receive_sender="org.bluez.Manager"/>
+
+ <allow send_destination="org.bluez.Adapter"/>
+ <allow receive_sender="org.bluez.Adapter"/>
+
+ <allow send_destination="org.bluez.Device"/>
+ <allow receive_sender="org.bluez.Device"/>
+
+ <allow send_destination="org.bluez.Service"/>
+ <allow receive_sender="org.bluez.Service"/>
+
+ <allow send_destination="org.bluez.Database"/>
+ <allow receive_sender="org.bluez.Database"/>
+
+ <allow send_destination="org.bluez.Security"/>
+ <allow receive_sender="org.bluez.Security"/>
+ </policy>
+
+</busconfig>
diff --git a/utils/hcid/dbus-api.txt b/utils/hcid/dbus-api.txt
new file mode 100644
index 00000000..622477be
--- /dev/null
+++ b/utils/hcid/dbus-api.txt
@@ -0,0 +1,1401 @@
+D-Bus API description for BlueZ
+*******************************
+
+Copyright (C) 2004-2007 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) 2005-2006 Eduardo Rocha <eduardo.rocha@indt.org.br>
+
+
+Constant definitions
+====================
+
+The class of device definition from the Bluetooth specification divides into
+three different parts. It the major class, the minor class and the service
+classes. The D-Bus interface will always use string constants to identify
+any of these classes.
+
+Service classes positioning, networking, rendering, capturing,
+ object transfer, audio, telephony, information
+
+Major classes miscellaneous, computer, phone, access point,
+ audio/video, peripheral, imaging, wearable, toy,
+ uncategorized
+
+Minor classes computer uncategorized, desktop, server, laptop, handheld,
+ palm, wearable
+
+Minor classes phone uncategorized, cellular, cordless, smart phone,
+ modem, isdn
+
+Minor classes access point fully, 1-17 percent, 17-33 percent,
+ 33-50 percent, 50-67 percent, 67-83 percent,
+ 83-99 percent, not available
+
+Minor classes audio video uncategorized, headset, handsfree,microphone,
+ loudspeaker, headphones, portable audio, car audio,
+ set-top box, hifi audio, vcr, video camera, camcorder,
+ video monitor, video display and loudspeaker,
+ video conferencing, gaming/toy, unknown
+
+Minor classes peripheral uncategorized, keyboard, pointing, combo
+
+Minor classes imaging display, camera, scanner, printer
+
+Minor classes wearable wrist watch, pager, jacket, helmet, glasses
+
+Minor classes toy robot, vehicle, doll, controller, game
+
+Error hierarchy
+===============
+
+Interface org.bluez.Error
+
+Shared Errors (Can be thrown by hcid or any bluetooth service)
+
+ DeviceUnreachable
+
+ The remote device is either powered down or out of range.
+
+ AlreadyConnected
+ A connection request has been received on an already
+ connected device.
+
+ ConnectionAttemptFailed
+
+ An unexpected error (other than DeviceUnreachable) error
+ has occured while attempting a connection to a device.
+
+ NotConnected
+ The remote device is not connected, while the method call
+ would expect it to be, or is not in the expected state to
+ perform the action.
+
+ InProgress
+
+ Error returned if an operation is in progress. Since
+ this is a generic error that can be used in various
+ situations, the error message should be more clear
+ about what is in progress. For example "Bonding in
+ progress".
+
+ InvalidArguments
+
+ The DBUS request does not contain the right number of
+ arguments with the right type, or the arguments are there
+ but their value is wrong, or does not makes sense in the
+ current context.
+
+ OutOfMemory
+
+ Error returned when a memory allocation via malloc()
+ fails. This error is similar to ENOMEM.
+
+ NotAvailable
+
+ Error returned when a specified record is not
+ available.
+
+ NotSupported
+
+ The remote device does not support the expected
+ feature.
+
+ AlreadyExists
+ One of the requested elements already exists
+
+ DoesNotExist
+ One of the requested elements does not exist
+
+ Canceled
+ The operation was canceled.
+
+ Failed
+
+ This is a the most generic error.
+ It is thrown when something unexpected happens.
+
+
+Hcid specific Errors (Can be thrown by hcid only)
+
+ NotReady
+
+ Error returned when the adapter is DOWN.
+
+ UnknwownMethod
+
+ This is an experimental method.
+
+ NotAuthorized
+
+ Error returned when the caller of a method is not
+ authorized. This might happen if a caller tries to
+ terminate a connection that it hasn't created.
+
+ Rejected
+
+ NoSuchAdapter
+
+ Error returned when the requested adapter doesn't
+ exists. This error is similar to ENODEV.
+
+ NoSuchService
+
+ RequestDeferred
+
+ NotInProgress
+
+ UnsupportedMajorClass
+
+ AuthenticationCanceled
+
+ AuthenticationFailed
+
+ AuthenticationTimeout
+
+ AuthenticationRejected
+
+ RepeatedAttempts
+
+Manager hierarchy
+=================
+
+Service org.bluez
+Interface org.bluez.Manager
+Object path /org/bluez
+
+Methods uint32 InterfaceVersion()
+
+ Returns the current interface version. At the moment
+ only version 0 is supported.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ string DefaultAdapter()
+
+ Returns object path for the default adapter.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NoSuchAdapter
+
+ string FindAdapter(string pattern)
+
+ Returns object path for the specified adapter. Valid
+ patterns are "hci0" or "00:11:22:33:44:55".
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NoSuchAdapter
+
+ array{string} ListAdapters()
+
+ Returns list of adapter object paths under /org/bluez
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+ org.bluez.Error.OutOfMemory
+
+ string FindService(string pattern)
+
+ Returns object path for the specified service. Valid
+ patterns are the unqiue identifier or a bus name.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NoSuchService
+
+ array{string} ListServices()
+
+ Returns list of object paths of current services.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ string ActivateService(string pattern)
+
+ Returns the unqiue bus id of the specified service.
+ Valid patterns are the same as for FindService(). If
+ the service is not running it will be started.
+
+Signals void AdapterAdded(string path)
+
+ Parameter is object path of added adapter.
+
+ void AdapterRemoved(string path)
+
+ Parameter is object path of removed adapter.
+
+ void DefaultAdapterChanged(string path)
+
+ Parameter is object path of the new default adapter,
+ or an empty string if there is no available adapters.
+
+ void ServiceAdded(string path)
+
+ Parameter is object path of registered service agent.
+
+ void ServiceRemoved(string path)
+
+ Parameter is object path of unregistered service agent.
+
+
+Database hierarchy
+==================
+
+Service org.bluez
+Interface org.bluez.Database
+Object path /org/bluez
+
+Methods uint32 AddServiceRecord(array{byte})
+
+ Adds a new service record and returns the assigned
+ record handle.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ uint32 AddServiceRecordFromXML(string record)
+
+ Adds a new service record and returns the assigned
+ record handle.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void UpdateServiceRecord(uint32 handle, array{byte})
+
+ Updates a given service record.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+ org.bluez.Error.Failed
+
+ void UpdateServiceRecordFromXML(uint32 handle, string record)
+
+ Updates a given service record provided in the
+ XML format.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+ org.bluez.Error.Failed
+
+ void RemoveServiceRecord(uint32 handle)
+
+ Remove a service record identified by its handle.
+
+ It is only possible to remove service records that
+ where added by the current connection.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAuthorized
+ org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+
+Adapter hierarchy
+=================
+
+Service org.bluez
+Interface org.bluez.Adapter
+Object path /org/bluez/{hci0,hci1,...}
+
+Methods dict GetInfo()
+
+ Returns the properties of the local adapter.
+
+ Possible errors: org.bluez.Error.NotReady
+
+ string GetAddress()
+
+ Returns the device address for a given path.
+
+ Example: "00:11:22:33:44:55"
+
+ Possible errors: org.bluez.Error.NotReady
+
+ string GetVersion()
+
+ Returns the version of the Bluetooth chip. This version
+ is compiled from the LMP version. In case of EDR the
+ features attribute must be checked.
+
+ Example: "Bluetooth 2.0 + EDR"
+
+ Possible errors: none
+
+ string GetRevision()
+
+ Returns the revision of the Bluetooth chip. This is a
+ vendor specific value and in most cases it represents
+ the firmware version. This might derive from the HCI
+ revision and LMP subversion values or via extra vendor
+ specific commands.
+
+ In case the revision of a chip is not available. This
+ method should return the LMP subversion value as a
+ string.
+
+ Example: "HCI 19.2"
+
+ Possible errors: org.bluez.Error.Failed
+
+ string GetManufacturer()
+
+ Returns the manufacturer of the Bluetooth chip. If
+ the company id is not know the sting "Company ID %d"
+ where %d should be replaced with the numeric value
+ from the manufacturer field.
+
+ Example: "Cambridge Silicon Radio"
+
+ Possible errors: org.bluez.Error.Failed
+
+ string GetCompany()
+
+ Returns the company name from the OUI database of the
+ Bluetooth device address. This function will need a
+ valid and up-to-date oui.txt from the IEEE. This value
+ will be different from the manufacturer string in the
+ most cases.
+
+ If the oui.txt file is not present or the OUI part of
+ the BD_ADDR is not listed, it should return the
+ string "OUI %s" where %s is the actual OUI.
+
+ Example: "Apple Computer"
+
+ Possible errors: org.bluez.Error.Failed
+
+ array{string} ListAvailableModes()
+
+ Returns a list of available modes the adapter can
+ be switched into.
+
+ string GetMode()
+
+ Returns the current mode of a adapter.
+
+ Valid modes: "off", "connectable", "discoverable",
+ "limited".
+
+ Possible errors: none
+
+ void SetMode(string mode)
+
+ Sets mode of the adapter. See GetMode for valid strings
+ for the mode parameter. In addition to the valid strings
+ for GetMode, this method also supports a special
+ parameter value "on" which will change the mode to the
+ previous non-off mode (or do nothing if the current
+ mode isn't "off").
+
+ Possible errors: org.bluez.Error.NoSuchAdapter
+ org.bluez.Error.Failed
+
+ uint32 GetDiscoverableTimeout()
+
+ Returns the discoverable timeout in seconds. A value
+ of zero means that the timeout is disabled and it will
+ stay in discoverable/limited mode forever.
+
+ The default value for the discoverable timeout should
+ be 180 seconds (3 minutes).
+
+ Possible errors: none
+
+ void SetDiscoverableTimeout(uint32 timeout)
+
+ Sets the discoverable timeout in seconds. A value of
+ zero disables the timeout and the adapter would be
+ always discoverable/limited.
+
+ Changing this value doesn't set the adapter into
+ discoverable/limited mode. The SetMode method must be used.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.InvalidArguments
+
+ boolean IsConnectable()
+
+ Returns true if the local adapter is connectable and
+ false if it is switched off.
+
+ It is also possible to use GetMode to retrieve this
+ information.
+
+ Possible errors: none
+
+ boolean IsDiscoverable()
+
+ Returns true if the local adapter is discoverable/limited
+ and false if it is only connectable or switched off.
+
+ It is also possible to use GetMode to retrieve this
+ information.
+
+ Possible errors: none
+
+ boolean IsConnected(string address)
+
+ Return true if the local adapter is connected to
+ the remote device.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ array{string} ListConnections()
+
+ Returns a list with addresses of currently connected
+ remote devices.
+
+ Possible errors: none
+
+ string GetMajorClass()
+
+ Returns the current major class value for this
+ system. Currently, only "computer" is supported.
+ For the other values, unsupported major class
+ error is returned.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.UnsupportedMajorClass
+
+ array{string} ListAvailableMinorClasses()
+
+ Returns a list of available minor classes for the
+ currently used major class. At the moment this should
+ only return a list of minor classes if the major
+ class is set to "computer".
+
+ If the major class is not "computer" an error should
+ be returned.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.UnsupportedMajorClass
+
+ string GetMinorClass()
+
+ Returns the current minor class value for this
+ system where the default major class is "computer".
+
+ If the major class is not "computer" an error should
+ be returned.
+
+ Valid values: "uncategorized", "desktop", "server",
+ "laptop", "handheld", "palm", "wearable"
+
+ The default value is "uncategorized".
+
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.UnsupportedMajorClass
+
+ void SetMinorClass(string minor)
+
+ Sets the local minor class and on success it sends
+ a MinorClassChanged signal.
+
+ If the major class is not "computer" an error should
+ be returned.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.InvalidArguments
+ org.bluez.Error.NoSuchAdapter
+ org.bluez.Error.Failed
+ org.bluez.Error.UnsupportedMajorClass
+
+ array{string} GetServiceClasses()
+
+ Returns the current set of service classes.
+
+ In the case no service classes are set (when no
+ service has been registered) an empty list should
+ be returned.
+
+ Valid values: "positioning", "networking", "rendering",
+ "capturing", "object transfer", "audio",
+ "telephony", "information"
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.NoSuchAdapter
+ org.bluez.Error.Failed
+
+ string GetName()
+
+ Returns the local adapter name (friendly name) in UTF-8.
+
+ Possible errors: org.bluez.Error.Failed
+
+ void SetName(string name)
+
+ Sets the local adapter name. If EIR is supported by
+ the local hardware this modifies also the extended
+ response data value.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ Questions: What to do (in case of EIR) if one
+ low-level API call fails.
+
+ dict GetRemoteInfo(string address)
+
+ Returns the properties for a remote device.
+
+ string GetRemoteVersion(string address)
+
+ Get the version info for a remote device. This request
+ returns always this information based on its cached
+ data. The base for this string is the LMP version
+ value and the features for EDR support.
+
+ Not available can be received if the remote device was
+ not contacted(connected) previously. Remote data is
+ automatically retrieved in the first connection.
+
+ Example: "Bluetooth 2.0 + EDR"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ string GetRemoteRevision(string address)
+
+ Get the revision of the Bluetooth chip. This is a
+ vendor specific value and in most cases it represents
+ the firmware version. This derives only from the LMP
+ subversion value.
+
+ Example: "HCI 19.2"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ string GetRemoteManufacturer(string address)
+
+ Get the manufacturer of the chip for a remote device.
+
+ Example: "Nokia Mobile Phones"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ string GetRemoteCompany(string address)
+
+ Get the company name from the OUI database of the
+ Bluetooth device address. This function will need a
+ valid and up-to-date oui.txt from the IEEE. This value
+ will be different from the manufacturer string in the
+ most cases.
+
+ Example: "Microsoft Corporation"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ string GetRemoteMajorClass(string address)
+
+ Get the major device class of the specified device.
+
+ Example: "computer"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ string GetRemoteMinorClass(string address)
+
+ Get the minor device class of the specified device.
+
+ Example: "laptop"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ array{string} GetRemoteServiceClasses(string address)
+
+ Get the service classes of the specified device.
+
+ Example: ["networking", "object transfer"]
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ uint32 GetRemoteClass(string address)
+
+ Get the remote major, minor, and service classes
+ encoded as 32 bit integer.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ array{byte} GetRemoteFeatures(string address)
+
+ Get the remote features encoded as bit mask.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ string GetRemoteName(string address)
+
+ Get the remote device's name. This request returns always
+ a cached name. The service daemon is responsible for
+ updating the cache.
+
+ NotAvailable error is returned if the name is not in
+ the cache. But if there is a discovery running, then
+ this function will return RequestDeferred. In this
+ case the service daemon will queue the request and
+ it will try to resolve the name at the next possible
+ opportunity. On success a RemoteNameUpdated signal will
+ be send and if a failure happens it will be indicated by
+ a RemoteNameFailed signal.
+
+ If this is an empty string, the UI might want to
+ display the BD_ADDR instead.
+
+ Example: "00:11:22:33:44:55", "Nokia 770"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+ org.bluez.Error.NotReady
+ org.bluez.Error.RequestDeferred
+
+ string GetRemoteAlias(string address)
+
+ Returns alias name for remote device. If this is
+ an empty string value, the UI should show the
+ remote name instead.
+
+ An alias should supersede the remote name.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ void SetRemoteAlias(string address, string alias)
+
+ Sets alias name for remote device. If alias name is
+ empty, then no alias is set.
+
+ On success the SetRemoteAlias method will produce a
+ RemoteAliasChanged signal which applications can use
+ to update their current display of the remote device
+ name.
+
+ Possible errors: org.bluez.Error.Failed
+ org.bluez.Error.InvalidArguments
+
+ void ClearRemoteAlias(string address)
+
+ Resets alias name for remote device. If there is no
+ alias set for the device this method will silently
+ succeed, but no RemoteAliasCleared signal has to be
+ sent in this case.
+
+ On success the ClearRemoteAlias method will produce
+ a RemoteAliasCleared signal.
+
+ Possible errors: org.bluez.Error.Failed
+ org.bluez.Error.InvalidArguments
+
+ string LastSeen(string address)
+
+ Returns the date and time when the adapter has been
+ seen by a discover procedure.
+
+ Example: "2006-02-08 12:00:00 GMT"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ Question: Can we find a better name?
+
+ string LastUsed(string address)
+
+ Returns the date and time of the last time when the
+ adapter has been connected.
+
+ Example: "2006-02-08 12:00:00 GMT"
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+
+ Question: Can we find a better name?
+
+ void DisconnectRemoteDevice(string address)
+
+ This method disconnects a specific remote device by
+ terminating the low-level ACL connection. The use of
+ this method should be restricted to administrator
+ use.
+
+ A RemoteDeviceDisconnectRequested signal will be
+ sent and the actual disconnection will only happen 2
+ seconds later. This enables upper-level applications
+ to terminate their connections gracefully before the
+ ACL connection is terminated.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.NoSuchAdapter
+ org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotConnected
+ org.bluez.Error.InProgress
+
+ void CreateBonding(string address)
+
+ This method creates a bonding with a remote device.
+
+ If a link key for this adapter already exists, this
+ procedure should fail instead of trying to create a
+ new pairing.
+
+ If no connection to the remote device exists, a
+ low-level ACL connection must be created.
+
+ This function will block and the calling application
+ should take care of setting are higher timeout. This
+ might be needed in case of a page timeout from the
+ low-level HCI commands.
+
+ In case of success it will send a BondingCreated
+ signal.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+ org.bluez.Error.InProgress
+ org.bluez.Error.NoSuchAdapter
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.AuthenticationFailed
+ org.bluez.Error.AuthenticationTimeout
+ org.bluez.Error.AuthenticationRejected
+ org.bluez.Error.AuthenticationCanceled
+
+ void CancelBondingProcess(string address)
+
+ This method will cancel the CreateBonding process.
+
+ The CreateBonding method will return
+ AuthenticationCanceled to signal that an attempt to
+ create a bonding has been canceled.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotInProgress
+ org.bluez.Error.NotAuthorized
+
+ void RemoveBonding(string address)
+
+ This method removes the bonding with a remote device.
+
+ For security reasons this includes removing the actual
+ link key and also disconnecting any open connections
+ for the remote device.
+
+ If the link key was stored on the Bluetooth chip, it
+ must be removed from there, too.
+
+ After deleting the link key this method will send a
+ BondingRemoved signal.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InvalidArguments
+ org.bluez.Error.NoSuchAdapter
+ org.bluez.Error.DoesNotExist
+
+ boolean HasBonding(string address)
+
+ Returns true if the remote device is bonded and false
+ if no link key is available.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ array{string} ListBondings()
+
+ List device addresses of currently bonded adapter.
+
+ Possible errors: none
+
+ uint8 GetPinCodeLength(string address)
+
+ Returns the PIN code length that was used in the
+ pairing process.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.DoesNotExist
+
+ uint8 GetEncryptionKeySize(string address)
+
+ Returns the currently used encryption key size.
+
+ This method will fail if no connection to the address
+ has been established.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
+
+ void SetTrusted(string address)
+
+ Marks the remote device as trusted. Authorization
+ request will automatically succeed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+
+ boolean IsTrusted(string address)
+
+ Returns true if the user is trusted or false otherwise.
+ The address parameter must match one of the remote
+ devices of the service.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ void RemoveTrust(string address)
+
+ Marks the remote device as not trusted.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.DoesNotExist
+
+ array{string} ListTrusts()
+
+ Returns a list of remote devices that are trusted.
+
+ void DiscoverDevices()
+
+ This method starts the device discovery procedure. This
+ includes an inquiry procedure and remote device name
+ resolving.
+
+ On start up this process will generate a DiscoveryStarted
+ signal and then return RemoteDeviceFound and also
+ RemoteNameUpdated signals. If the procedure has been
+ finished an DiscoveryCompleted signal will be sent.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InProgress
+ org.bluez.Error.NoSuchAdapter
+
+ void DiscoverDevicesWithoutNameResolving()
+
+ This method starts the device discovery procedure. This
+ includes an inquiry and an optional remote device name
+ resolving. The remote names can be retrieved with
+ GetRemoteName and in the case a name doesn't exist it
+ will be queued for later resolving and GetRemoteName
+ will return an error.
+
+ While this procedure is running every found device
+ will be returned with RemoteDeviceFound. While
+ DiscoverDevices() automatically resolves unknown
+ devices names and sends RemoteNameUpdated in this
+ case it will only happen if GetRemoteName has been
+ called and no previously stored name is available.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InProgress
+ org.bluez.Error.NoSuchAdapter
+
+ void CancelDiscovery()
+
+ This method will cancel any previous DiscoverDevices
+ or DiscoverDevicesWithoutNameResolving actions.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.NotAuthorized
+ org.bluez.Error.NoSuchAdapter
+
+ void StartPeriodicDiscovery()
+
+ This method starts a periodic discovery.
+
+ Possible errors: org.bluez.error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.InProgress
+ org.bluez.Error.NoSuchAdapter
+
+ void StopPeriodicDiscovery()
+
+ This method stops a periodic discovery. If the
+ adapter is not in the periodic inquiry mode an
+ error(not authorized) is returned. Everyone can
+ request exit from this mode, it is not restricted
+ to start requestor.
+
+ Possible errors: org.bluez.Error.NotReady
+ org.bluez.Error.Failed
+ org.bluez.Error.NotAuthorized
+ org.bluez.Error.NoSuchAdapter
+
+ boolean IsPeriodicDiscovery()
+
+ Returns true if the periodic inquiry is active and
+ false if it is switched off.
+
+ Possible errors: none
+
+ void SetPeriodicDiscoveryNameResolving(boolean resolve_names)
+
+ Enable or disable automatic remote name resolving for
+ periodic discovery.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ boolean GetPeriodicDiscoveryNameResolving()
+
+ Check if automatic remote name resolving is enabled or not
+ for periodic discovery.
+
+ Possible error: org.bluez.Error.InvalidArguments
+
+ array{uint32} GetRemoteServiceHandles(string address, string match)
+
+ This method will request the SDP database of a remote
+ device and retrieve the service record handles. To
+ request service browse send an empty match string.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.InProgress
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.Failed
+
+ array{byte} GetRemoteServiceRecord(string address, uint32 handle)
+
+ This method will request the SDP database of a remote
+ device for a service record and return the binary
+ stream of it.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.InProgress
+ org.bluez.Error.Failed
+
+ string GetRemoteServiceRecordAsXML(string address, uint32 handle)
+
+ This method will request the SDP database of a remote
+ device for a service record and return its data in XML
+ format.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.InProgress
+ org.bluez.Error.Failed
+
+ array{string} GetRemoteServiceIdentifiers(string address)
+
+ This method will request the SDP database of a remote
+ device for all supported services. The identifiers are
+ returned in UUID 128 string format.
+
+ Possible errors: org.bluez.Error.InProgress
+ org.bluez.Error.Failed
+
+ void FinishRemoteServiceTransaction(string address)
+
+ This method will finish all SDP transaction for that
+ given address. In general this call is not needed,
+ but in cases of resources restricted devices it
+ is useful to call this to finish the SDP transaction
+ before proceeded with profile specific connections.
+
+ array{string} ListRemoteDevices()
+
+ List addresses of all known remote devices (bonded,
+ trusted and used).
+
+ Possible errors: none
+
+ array{string} ListRecentRemoteDevices(string date)
+
+ List addresses of all bonded, trusted, seen or used remote
+ devices since date. Bonded and trusted devices are always
+ included(the date informed is not applied).
+
+ date format is "YYYY-MM-DD HH:MM:SS GMT"
+
+ Possible errors: none
+
+Signals void ModeChanged(string mode)
+
+ If the current mode is changed with SetMode this signal
+ will inform about the new mode.
+
+ This signal can also be triggered by low-level HCI
+ commands.
+
+ void DiscoverableTimeoutChanged(uint32 timeout)
+
+ After changing the discoverable timeout this signal
+ provide the new timeout value.
+
+ void MinorClassChanged(string minor)
+
+ After changing the minor class with SetMinorClass this
+ signal will provide the new class value.
+
+ void NameChanged(string name)
+
+ After changing the local adapter name with SetName this
+ signal will provide the new name.
+
+ This signal can also be triggered by low-level HCI
+ commands.
+
+ void DiscoveryStarted()
+
+ This signal indicates that a device discovery
+ procedure has been started.
+
+ void DiscoveryCompleted()
+
+ This signal indicates that a device discovery
+ procedure has been completed.
+
+ void PeriodicDiscoveryStarted()
+
+ This signal indicates that a periodic discovery
+ procedure has been started.
+
+ void PeriodicDiscoveryStopped()
+
+ This signal indicates that a periodic discovery
+ procedure has been completed.
+
+ void RemoteDeviceFound(string address, uint32 class, int16 rssi)
+
+ This signal will be send every time an inquiry result
+ has been found by the service daemon. In general they
+ only appear during a device discovery.
+
+ void RemoteDeviceDisappeared(string address)
+
+ This signal will be send when an inquiry session for
+ a periodic discovery finishes and previously found
+ devices are no longer in range or visible.
+
+ void RemoteClassUpdated(string address, uint32 class)
+
+ This signal will be send every time the remote class
+ of device has been changed. This happens for example
+ after a remote connection attempt. This signal will
+ not be send if the class of device hasn't changed
+ compared to cached one.
+
+ void RemoteNameUpdated(string address, string name)
+
+ This signal will be send every time the service daemon
+ detect a new name for a remote device.
+
+ void RemoteIdentifiersUpdated(string address, array{string identifiers})
+
+ This signal is sent to indicate the provided services of a given
+ remote device. It will be sent after GetRemoteServiceIdentifiers
+ calls. This signal has at least one identifier and it does not
+ contain repeated entries.
+
+ void RemoteNameFailed(string address)
+
+ This signal will be sent every time the service daemon
+ tries to resolve a remote and this fails.
+
+ void RemoteNameRequested(string address)
+
+ This signal will be sent every time the service daemon
+ tries to resolve a remote name during discovery.
+
+ void RemoteAliasChanged(string address, string alias)
+
+ After changing an alias with SetRemoteAlias this
+ signal will indicate the new alias.
+
+ void RemoteAliasCleared(string address)
+
+ After removing an alias with ClearRemoteAlias this
+ signal will indicate that the alias is no longer
+ valid.
+
+ void RemoteDeviceConnected(string address)
+
+ This signal will be send if a low level connection
+ between two devices has been created.
+
+ void RemoteDeviceDisconnectRequested(string address)
+
+ This signal will be sent when a low level
+ disconnection to a remote device has been requested.
+ The actual disconnection will happen 2 seconds later.
+
+ void RemoteDeviceDisconnected(string address)
+
+ This signal will be send if a low level connection
+ between two devices has been terminated.
+
+ void BondingCreated(string address)
+
+ Signals that a successful bonding has been created.
+
+ void BondingRemoved(string address)
+
+ Signals that a bonding was removed.
+
+ void TrustAdded(string address)
+
+ Sent when SetTrusted() is called.
+
+ void TrustRemoved(string address)
+
+ Sent when RemoveTrust() is called.
+
+Service hierarchy
+=================
+
+Service org.bluez
+Interface org.bluez.Service
+Object path path from org.bluez.Manager.ListServices()
+
+Methods dict GetInfo()
+
+ Returns the service properties.
+
+ string GetIdentifier()
+
+ This method returns the service identifier.
+
+ string GetName()
+
+ This method returns the service name.
+
+ string GetDescription()
+
+ This method returns the service description.
+
+ string GetBusName() [experimental]
+
+ Returns the unique bus name of the service if it has
+ been started.
+
+ Possible errors: org.bluez.Error.NotAvailable
+
+ void Start()
+
+ This method tells the system to start the
+ service.
+
+ void Stop()
+
+ This method tells the system to stop the
+ service.
+
+ boolean IsRunning()
+
+ Returns true if the service has been started and
+ is currently active. Otherwise, it returns false.
+
+ boolean IsExternal()
+
+ Returns true if the service was registered using the
+ Database.RegisterService method instead of a .service
+ file. The Start and Stop methods are not applicable to
+ external services and will return an error.
+
+ array{string} ListTrusts() [experimental]
+
+ Returns a list of remote devices that are trusted
+ for the service.
+
+ void SetTrusted(string address) [experimental]
+
+ Marks the user as trusted.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+
+ boolean IsTrusted(string address) [experimental]
+
+ Returns true if the user is trusted or false otherwise.
+ The address parameter must match one of the
+ current users of the service.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ void RemoveTrust(string address) [experimental]
+
+ Marks the user as not trusted.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.DoesNotExist
+
+Signals void Started()
+
+ The object path of this signal contains which service
+ was started.
+
+ void Stopped()
+
+ The object path of this signal contains which service
+ was stopped.
+
+ void TrustAdded(string address)
+
+ Sent when SetTrusted() is called.
+
+ void TrustRemoved(string address)
+
+ Sent when RemoveTrust() is called.
+
+
+Security hierarchy
+==================
+
+Service org.bluez
+Interface org.bluez.Security
+Object path /org/bluez or /org/bluez/{hci0,hci1,...}
+
+Methods void RegisterDefaultPasskeyAgent(string path)
+
+ This registers the default passkey agent. It can
+ register a passkey for all adapters or for a
+ specific device depending on with object path has
+ been used.
+
+ The path parameter defines the object path of the
+ passkey agent that will be called when a passkey
+ needs to be entered.
+
+ If an application disconnects from the bus all
+ registered passkey agent will be removed.
+
+ Possible errors: org.bluez.Error.AlreadyExists
+
+ void UnregisterDefaultPasskeyAgent(string path)
+
+ This unregisters a default passkey agent that has
+ been previously registered. The object path and
+ the path parameter must match the same values that
+ has been used on registration.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+ void RegisterPasskeyAgent(string path, string address)
+
+ This registers the application passkey agent that
+ will be used for any application specific passkey
+ tasks.
+
+ The path parameter defines the object path of the
+ passkey agent that will be called when a passkey
+ needs to be entered. The address defines the remote
+ device that it will answer passkey requests for.
+
+ If an application disconnects from the bus all
+ registered passkey agent will be removed. It will
+ also be unregistered after a timeout and if the
+ pairing succeeds or fails. The application has to
+ take care of that it reregisters the passkey agent.
+
+ Possible errors: org.bluez.Error.AlreadyExists
+
+ void UnregisterPasskeyAgent(string path, string address)
+
+ This unregisters a passkey agent that has been
+ previously registered. The object path and the path
+ and address parameter must match the same values
+ that has been used on registration.
+
+ The method is actually only needed if an application
+ wants to removed the passkey agent and don't wanna
+ wait for the automatic timeout.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+ void RegisterDefaultAuthorizationAgent(string path)
+
+ This registers the default authorization agent. It can
+ register an authorization agent for all adapters or
+ for a specific one depending on which object path has
+ been used.
+
+ The path parameter defines the object path of the
+ authorization agent that will be called when an
+ authorization request needs to be answered.
+
+ void UnregisterDefaultAuthorizationAgent(string path)
+
+ This unregisters a default authorization agent that has
+ been previously registered. The path parameter must
+ match the same value that has been used on
+ registration.
+
+
+PasskeyAgent hierarchy
+======================
+
+Service unique name
+Interface org.bluez.PasskeyAgent
+Object path freely definable
+
+Methods string Request(string path, string address)
+
+ This method gets called when the service daemon
+ needs to get the passkey for an authentication. The
+ return value is actual passkey. It is a 1 to 16
+ byte PIN code in UTF-8 format.
+
+ The first argument contains the path of the local
+ adapter and the second one the remote address.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void Cancel(string path, string address)
+
+ This method gets called to indicate that the
+ authentication request failed before a reply was
+ returned by the Request method.
+
+ void Release()
+
+ This method gets called when the service daemon
+ unregisters a passkey 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.
+
+
+AuthorizationAgent hierarchy (experimental)
+===========================================
+
+Service unique name
+Interface org.bluez.AuthorizationAgent
+Object path freely definable
+
+Methods void Authorize(string adapter_path, string address,
+ string service_path, string uuid)
+
+ This method gets called when the service daemon wants
+ to get an authorization for accessing a service. This
+ method should return if the remote user is granted
+ access or an error otherwise.
+
+ The adapter_path parameter is the object path of the
+ local adapter. The address, service_path and action
+ parameters correspond to the remote device address,
+ the object path of the service and the uuid of the
+ profile.
+
+ Possible errors: org.bluez.Error.Rejected
+ org.bluez.Error.Canceled
+
+ void Cancel(string adapter_path, string address,
+ string service_path, string uuid)
+
+ This method cancels a previous authorization request.
+ The adapter_path, address, service_path and uuid
+ parameters must match the same values that have been
+ used when the Authorize() method was called.
+
+ void Release()
+
+ This method gets called when the service daemon
+ unregisters an authorization 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.
diff --git a/utils/hcid/dbus-common.c b/utils/hcid/dbus-common.c
new file mode 100644
index 00000000..99585d0a
--- /dev/null
+++ b/utils/hcid/dbus-common.c
@@ -0,0 +1,364 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "manager.h"
+#include "adapter.h"
+#include "dbus-hci.h"
+#include "dbus-service.h"
+#include "dbus-database.h"
+#include "dbus-security.h"
+#include "dbus-sdp.h"
+#include "dbus-common.h"
+
+#define BLUEZ_NAME "org.bluez"
+
+#define RECONNECT_RETRY_TIMEOUT 5000
+
+static int experimental = 0;
+
+int l2raw_connect(const char *local, const bdaddr_t *remote)
+{
+ struct sockaddr_l2 addr;
+ long arg;
+ int sk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (sk < 0) {
+ error("Can't create socket: %s (%d)", strerror(errno), errno);
+ return sk;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba(local, &addr.l2_bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ error("Can't bind socket: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ arg = fcntl(sk, F_GETFL);
+ if (arg < 0) {
+ error("Can't get file flags: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ arg |= O_NONBLOCK;
+ if (fcntl(sk, F_SETFL, arg) < 0) {
+ error("Can't set file flags: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, remote);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (errno == EAGAIN || errno == EINPROGRESS)
+ return sk;
+ error("Can't connect socket: %s (%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ return sk;
+
+failed:
+ close(sk);
+ return -1;
+}
+
+void hcid_dbus_set_experimental(void)
+{
+ experimental = 1;
+}
+
+int hcid_dbus_use_experimental(void)
+{
+ return experimental;
+}
+
+static gboolean system_bus_reconnect(void *data)
+{
+ DBusConnection *conn = get_dbus_connection();
+ struct hci_dev_list_req *dl = NULL;
+ struct hci_dev_req *dr;
+ int sk, i;
+ gboolean ret_val = TRUE;
+
+ if (conn) {
+ if (dbus_connection_get_is_connected(conn))
+ return FALSE;
+ }
+
+ if (hcid_dbus_init() < 0)
+ return TRUE;
+
+ /* Create and bind HCI socket */
+ sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (sk < 0) {
+ error("Can't open HCI socket: %s (%d)",
+ strerror(errno), errno);
+ return TRUE;
+ }
+
+ dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl));
+
+ dl->dev_num = HCI_MAX_DEV;
+ dr = dl->dev_req;
+
+ if (ioctl(sk, HCIGETDEVLIST, (void *) dl) < 0) {
+ info("Can't get device list: %s (%d)",
+ strerror(errno), errno);
+ goto failed;
+ }
+
+ /* reset the default device */
+ manager_set_default_adapter(-1);
+
+ for (i = 0; i < dl->dev_num; i++, dr++)
+ hcid_dbus_register_device(dr->dev_id);
+
+ ret_val = FALSE;
+
+failed:
+ if (sk >= 0)
+ close(sk);
+
+ g_free(dl);
+
+ return ret_val;
+}
+
+static void disconnect_callback(void *user_data)
+{
+ set_dbus_connection(NULL);
+
+ release_services(NULL);
+
+ g_timeout_add(RECONNECT_RETRY_TIMEOUT,
+ system_bus_reconnect, NULL);
+}
+
+void hcid_dbus_unregister(void)
+{
+ DBusConnection *conn = get_dbus_connection();
+ char **children;
+ int i;
+
+ if (!conn || !dbus_connection_get_is_connected(conn))
+ return;
+
+ /* Unregister all paths in Adapter path hierarchy */
+ if (!dbus_connection_list_registered(conn, BASE_PATH, &children))
+ return;
+
+ for (i = 0; children[i]; i++) {
+ char dev_path[MAX_PATH_LENGTH];
+
+ if (children[i][0] != 'h')
+ continue;
+
+ snprintf(dev_path, sizeof(dev_path), "%s/%s", BASE_PATH,
+ children[i]);
+
+ unregister_adapter_path(dev_path);
+ }
+
+ dbus_free_string_array(children);
+}
+
+void hcid_dbus_exit(void)
+{
+ DBusConnection *conn = get_dbus_connection();
+
+ if (!conn || !dbus_connection_get_is_connected(conn))
+ return;
+
+ release_default_agent_old();
+ release_default_auth_agent();
+ release_services(conn);
+
+ database_cleanup(conn, BASE_PATH);
+
+ manager_cleanup(conn, BASE_PATH);
+
+ set_dbus_connection(NULL);
+
+ dbus_connection_unref(conn);
+}
+
+int hcid_dbus_init(void)
+{
+ DBusConnection *conn;
+
+ conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, NULL);
+ if (!conn)
+ return -1;
+
+ if (g_dbus_set_disconnect_function(conn, disconnect_callback,
+ NULL, NULL) == FALSE) {
+ dbus_connection_unref(conn);
+ return -1;
+ }
+
+ if (!manager_init(conn, BASE_PATH))
+ return -1;
+
+ if (!database_init(conn, BASE_PATH))
+ return -1;
+
+ if (!security_init(conn, BASE_PATH))
+ return -1;
+
+ set_dbus_connection(conn);
+
+ return 0;
+}
+
+static void dbus_message_iter_append_variant(DBusMessageIter *iter,
+ int type, void *val)
+{
+ DBusMessageIter value;
+ DBusMessageIter array;
+ char *sig;
+
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ sig = DBUS_TYPE_STRING_AS_STRING;
+ break;
+ case DBUS_TYPE_BYTE:
+ sig = DBUS_TYPE_BYTE_AS_STRING;
+ break;
+ case DBUS_TYPE_INT16:
+ sig = DBUS_TYPE_INT16_AS_STRING;
+ break;
+ case DBUS_TYPE_UINT16:
+ sig = DBUS_TYPE_UINT16_AS_STRING;
+ break;
+ case DBUS_TYPE_INT32:
+ sig = DBUS_TYPE_INT32_AS_STRING;
+ break;
+ case DBUS_TYPE_UINT32:
+ sig = DBUS_TYPE_UINT32_AS_STRING;
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ sig = DBUS_TYPE_BOOLEAN_AS_STRING;
+ break;
+ case DBUS_TYPE_ARRAY:
+ sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
+ break;
+ case DBUS_TYPE_OBJECT_PATH:
+ sig = DBUS_TYPE_OBJECT_PATH_AS_STRING;
+ break;
+ default:
+ error("Could not append variant with type %d", type);
+ return;
+ }
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+ if (type == DBUS_TYPE_ARRAY) {
+ int i;
+ const char ***str_array = val;
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+
+ for (i = 0; (*str_array)[i]; i++)
+ dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+ &((*str_array)[i]));
+
+ dbus_message_iter_close_container(&value, &array);
+ } else
+ dbus_message_iter_append_basic(&value, type, val);
+
+ dbus_message_iter_close_container(iter, &value);
+}
+
+void dbus_message_iter_append_dict_entry(DBusMessageIter *dict,
+ const char *key, int type, void *val)
+{
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_append_variant(&entry, type, val);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+dbus_bool_t dbus_connection_emit_property_changed(DBusConnection *conn,
+ const char *path,
+ const char *interface,
+ const char *name,
+ int type, void *value)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ gboolean ret;
+
+ signal = dbus_message_new_signal(path, interface, "PropertyChanged");
+
+ if (!signal) {
+ error("Unable to allocate new %s.PropertyChanged signal",
+ interface);
+ return FALSE;
+ }
+
+ dbus_message_iter_init_append(signal, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_append_variant(&iter, type, value);
+
+ ret = dbus_connection_send(conn, signal, NULL);
+
+ dbus_message_unref(signal);
+ return ret;
+}
diff --git a/utils/hcid/dbus-common.h b/utils/hcid/dbus-common.h
new file mode 100644
index 00000000..afdf7569
--- /dev/null
+++ b/utils/hcid/dbus-common.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define BASE_PATH "/org/bluez"
+#define ADAPTER_PATH_INDEX 10
+
+#define MAX_PATH_LENGTH 64
+
+int str2uuid(uuid_t *uuid, const char *string);
+
+int l2raw_connect(const char *local, const bdaddr_t *remote);
+
+#define check_address(address) bachk(address)
+
+void hcid_dbus_exit(void);
+int hcid_dbus_init(void);
+void hcid_dbus_unregister(void);
+
+void dbus_message_iter_append_dict_entry(DBusMessageIter *dict,
+ const char *key, int type, void *val);
+
+dbus_bool_t dbus_connection_emit_property_changed(DBusConnection *conn,
+ const char *path,
+ const char *interface,
+ const char *name,
+ int type, void *value);
diff --git a/utils/hcid/dbus-database.c b/utils/hcid/dbus-database.c
new file mode 100644
index 00000000..ab88c8f5
--- /dev/null
+++ b/utils/hcid/dbus-database.c
@@ -0,0 +1,380 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "sdpd.h"
+#include "sdp-xml.h"
+#include "manager.h"
+#include "adapter.h"
+#include "dbus-hci.h"
+#include "dbus-common.h"
+#include "error.h"
+#include "dbus-service.h"
+#include "dbus-security.h"
+#include "dbus-database.h"
+
+static GSList *records = NULL;
+
+struct record_data {
+ uint32_t handle;
+ char *sender;
+ guint listener_id;
+};
+
+static struct record_data *find_record(uint32_t handle, const char *sender)
+{
+ GSList *list;
+
+ for (list = records; list; list = list->next) {
+ struct record_data *data = list->data;
+ if (handle == data->handle && !strcmp(sender, data->sender))
+ return data;
+ }
+
+ return NULL;
+}
+
+static void exit_callback(void *user_data)
+{
+ struct record_data *user_record = user_data;
+
+ debug("remove record");
+
+ records = g_slist_remove(records, user_record);
+
+ remove_record_from_server(user_record->handle);
+
+ g_free(user_record->sender);
+ g_free(user_record);
+}
+
+static inline DBusMessage *invalid_arguments(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ "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 *failed(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed");
+}
+
+static DBusMessage *add_service_record(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, array;
+ const char *sender;
+ struct record_data *user_record;
+ sdp_record_t *sdp_record;
+ const uint8_t *record;
+ int scanned, len = -1;
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_recurse(&iter, &array);
+
+ dbus_message_iter_get_fixed_array(&array, &record, &len);
+ if (len <= 0)
+ return invalid_arguments(msg);
+
+ sdp_record = sdp_extract_pdu_safe(record, len, &scanned);
+ if (!sdp_record) {
+ error("Parsing of service record failed");
+ return failed(msg);
+ }
+
+ if (scanned != len) {
+ error("Size mismatch of service record");
+ sdp_record_free(sdp_record);
+ return failed(msg);
+ }
+
+ if (add_record_to_server(BDADDR_ANY, sdp_record) < 0) {
+ error("Failed to register service record");
+ sdp_record_free(sdp_record);
+ return failed(msg);
+ }
+
+ user_record = g_new0(struct record_data, 1);
+
+ user_record->handle = sdp_record->handle;
+
+ sender = dbus_message_get_sender(msg);
+
+ user_record->sender = g_strdup(sender);
+
+ records = g_slist_append(records, user_record);
+
+ user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
+ exit_callback,
+ user_record,
+ NULL);
+
+ debug("listener_id %d", user_record->listener_id);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &user_record->handle,
+ DBUS_TYPE_INVALID);
+}
+
+int add_xml_record(DBusConnection *conn, const char *sender, bdaddr_t *src,
+ const char *record, dbus_uint32_t *handle)
+{
+ struct record_data *user_record;
+ sdp_record_t *sdp_record;
+
+ sdp_record = sdp_xml_parse_record(record, strlen(record));
+ if (!sdp_record) {
+ error("Parsing of XML service record failed");
+ return -EIO;
+ }
+
+ if (add_record_to_server(src, sdp_record) < 0) {
+ error("Failed to register service record");
+ sdp_record_free(sdp_record);
+ return -EIO;
+ }
+
+ user_record = g_new0(struct record_data, 1);
+
+ user_record->handle = sdp_record->handle;
+
+ user_record->sender = g_strdup(sender);
+
+ records = g_slist_append(records, user_record);
+
+ user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
+ exit_callback, user_record, NULL);
+
+ debug("listener_id %d", user_record->listener_id);
+
+ *handle = user_record->handle;
+
+ return 0;
+}
+
+static DBusMessage *add_service_record_from_xml(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *sender, *record;
+ dbus_uint32_t handle;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ sender = dbus_message_get_sender(msg);
+
+ err = add_xml_record(conn, sender, BDADDR_ANY, record, &handle);
+ if (err < 0)
+ return failed(msg);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
+ bdaddr_t *src, dbus_uint32_t handle, sdp_record_t *sdp_record)
+{
+ int err;
+
+ if (remove_record_from_server(handle) < 0) {
+ sdp_record_free(sdp_record);
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotAvailable",
+ "Not Available");
+ }
+
+ sdp_record->handle = handle;
+ err = add_record_to_server(src, sdp_record);
+ if (err < 0) {
+ sdp_record_free(sdp_record);
+ error("Failed to update the service record");
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ strerror(EIO));
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *update_service_record(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct record_data *user_record;
+ DBusMessageIter iter, array;
+ sdp_record_t *sdp_record;
+ dbus_uint32_t handle;
+ const uint8_t *bin_record;
+ int scanned, size = -1;
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_get_basic(&iter, &handle);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &array);
+
+ dbus_message_iter_get_fixed_array(&array, &bin_record, &size);
+ if (size <= 0)
+ return invalid_arguments(msg);
+
+ user_record = find_record(handle, dbus_message_get_sender(msg));
+ if (!user_record)
+ return not_available(msg);
+
+ sdp_record = sdp_extract_pdu_safe(bin_record, size, &scanned);
+ if (!sdp_record) {
+ error("Parsing of service record failed");
+ return invalid_arguments(msg);
+ }
+
+ if (scanned != size) {
+ error("Size mismatch of service record");
+ sdp_record_free(sdp_record);
+ return invalid_arguments(msg);
+ }
+
+ return update_record(conn, msg, BDADDR_ANY, handle, sdp_record);
+}
+
+DBusMessage *update_xml_record(DBusConnection *conn,
+ DBusMessage *msg, bdaddr_t *src)
+{
+ struct record_data *user_record;
+ sdp_record_t *sdp_record;
+ const char *record;
+ dbus_uint32_t handle;
+ int len;
+
+ if (dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_STRING, &record,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ len = (record ? strlen(record) : 0);
+ if (len == 0)
+ return invalid_arguments(msg);
+
+ user_record = find_record(handle, dbus_message_get_sender(msg));
+ if (!user_record)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotAvailable",
+ "Not Available");
+
+ sdp_record = sdp_xml_parse_record(record, len);
+ if (!sdp_record) {
+ error("Parsing of XML service record failed");
+ sdp_record_free(sdp_record);
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ strerror(EIO));
+ }
+
+ return update_record(conn, msg, src, handle, sdp_record);
+}
+
+static DBusMessage *update_service_record_from_xml(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return update_xml_record(conn, msg, BDADDR_ANY);
+}
+
+int remove_record(DBusConnection *conn, const char *sender,
+ dbus_uint32_t handle)
+{
+ struct record_data *user_record;
+
+ debug("remove record 0x%x", handle);
+
+ user_record = find_record(handle, sender);
+ if (!user_record)
+ return -1;
+
+ debug("listner_id %d", user_record->listener_id);
+
+ g_dbus_remove_watch(conn, user_record->listener_id);
+
+ exit_callback(user_record);
+
+ return 0;
+}
+
+static DBusMessage *remove_service_record(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ dbus_uint32_t handle;
+ const char *sender;
+
+ if (dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ sender = dbus_message_get_sender(msg);
+
+ if (remove_record(conn, sender, handle) < 0)
+ return not_available(msg);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable database_methods[] = {
+ { "AddServiceRecord", "ay", "u", add_service_record },
+ { "AddServiceRecordFromXML", "s", "u", add_service_record_from_xml },
+ { "UpdateServiceRecord", "uay", "", update_service_record },
+ { "UpdateServiceRecordFromXML", "us", "", update_service_record_from_xml },
+ { "RemoveServiceRecord", "u", "", remove_service_record },
+ { }
+};
+
+dbus_bool_t database_init(DBusConnection *conn, const char *path)
+{
+ return g_dbus_register_interface(conn, path, DATABASE_INTERFACE,
+ database_methods, NULL, NULL, NULL, NULL);
+}
+
+void database_cleanup(DBusConnection *conn, const char *path)
+{
+ g_dbus_unregister_interface(conn, path, DATABASE_INTERFACE);
+}
diff --git a/utils/hcid/dbus-database.h b/utils/hcid/dbus-database.h
new file mode 100644
index 00000000..c173afaf
--- /dev/null
+++ b/utils/hcid/dbus-database.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define DATABASE_INTERFACE "org.bluez.Database"
+
+dbus_bool_t database_init(DBusConnection *conn, const char *path);
+void database_cleanup(DBusConnection *conn, const char *path);
+
+int add_xml_record(DBusConnection *conn, const char *sender, bdaddr_t *src,
+ const char *record, dbus_uint32_t *handle);
+DBusMessage *update_xml_record(DBusConnection *conn,
+ DBusMessage *msg, bdaddr_t *src);
+int remove_record(DBusConnection *conn, const char *sender,
+ dbus_uint32_t handle);
diff --git a/utils/hcid/dbus-error.c b/utils/hcid/dbus-error.c
new file mode 100644
index 00000000..76d9f095
--- /dev/null
+++ b/utils/hcid/dbus-error.c
@@ -0,0 +1,91 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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 <bluetooth/sdp.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "dbus-common.h"
+#include "dbus-error.h"
+#include "error.h"
+
+static inline DBusHandlerResult send_message_and_unref(DBusConnection *conn,
+ DBusMessage *msg)
+{
+ if (msg) {
+ dbus_connection_send(conn, msg, NULL);
+ dbus_message_unref(msg);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult error_no_such_adapter(DBusConnection *conn, DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg, ERROR_INTERFACE ".NoSuchAdapter",
+ "No such adapter"));
+}
+
+DBusHandlerResult error_authentication_canceled(DBusConnection *conn, DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationCanceled",
+ "Authentication Canceled"));
+}
+
+static const char *strsdperror(int err)
+{
+ switch (err) {
+ case SDP_INVALID_VERSION:
+ return "Invalid/unsupported SDP version";
+ case SDP_INVALID_RECORD_HANDLE:
+ return "Invalid Service Record Handle";
+ case SDP_INVALID_SYNTAX:
+ return "Invalid request syntax";
+ case SDP_INVALID_PDU_SIZE:
+ return "Invalid PDU size";
+ case SDP_INVALID_CSTATE:
+ return "Invalid Continuation State";
+ default:
+ return "Undefined error";
+ }
+}
+
+DBusHandlerResult error_sdp_failed(DBusConnection *conn, DBusMessage *msg, int err)
+{
+ const char *str = strsdperror(err);
+
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg, ERROR_INTERFACE ".Failed", str));
+}
diff --git a/utils/hcid/dbus-error.h b/utils/hcid/dbus-error.h
new file mode 100644
index 00000000..6b3a22c4
--- /dev/null
+++ b/utils/hcid/dbus-error.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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
+ *
+ */
+
+/*
+ Please update dbus-api.txt in hcid folder when changes are made to this file.
+ */
+
+DBusHandlerResult error_no_such_adapter(DBusConnection *conn, DBusMessage *msg);
+/* Used only for hcid device audit feature */
+DBusHandlerResult error_authentication_canceled(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult error_auth_agent_does_not_exist(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult error_sdp_failed(DBusConnection *conn, DBusMessage *msg, int err);
diff --git a/utils/hcid/dbus-hci.c b/utils/hcid/dbus-hci.c
new file mode 100644
index 00000000..617ded21
--- /dev/null
+++ b/utils/hcid/dbus-hci.c
@@ -0,0 +1,2713 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "textfile.h"
+#include "manager.h"
+#include "adapter.h"
+#include "device.h"
+#include "error.h"
+#include "glib-helper.h"
+#include "dbus-common.h"
+#include "dbus-error.h"
+#include "dbus-service.h"
+#include "dbus-security.h"
+#include "agent.h"
+#include "dbus-hci.h"
+
+static DBusConnection *connection = NULL;
+
+void bonding_request_free(struct bonding_request_info *bonding)
+{
+ struct device *device;
+ char address[18];
+
+ if (!bonding)
+ return;
+
+ if (bonding->msg)
+ dbus_message_unref(bonding->msg);
+
+ if (bonding->conn)
+ dbus_connection_unref(bonding->conn);
+
+ if (bonding->io)
+ g_io_channel_unref(bonding->io);
+
+ ba2str(&bonding->bdaddr, address);
+
+ device = adapter_find_device(bonding->adapter, address);
+ if (device && device->agent) {
+ agent_destroy(device->agent, FALSE);
+ device->agent = NULL;
+ }
+
+ g_free(bonding);
+}
+
+int found_device_cmp(const struct remote_dev_info *d1,
+ const struct remote_dev_info *d2)
+{
+ int ret;
+
+ if (bacmp(&d2->bdaddr, BDADDR_ANY)) {
+ ret = bacmp(&d1->bdaddr, &d2->bdaddr);
+ if (ret)
+ return ret;
+ }
+
+ if (d2->name_status != NAME_ANY) {
+ ret = (d1->name_status - d2->name_status);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int dev_rssi_cmp(struct remote_dev_info *d1, struct remote_dev_info *d2)
+{
+ int rssi1, rssi2;
+
+ rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
+ rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
+
+ return rssi1 - rssi2;
+}
+
+int found_device_add(GSList **list, bdaddr_t *bdaddr, int8_t rssi,
+ name_status_t name_status)
+{
+ struct remote_dev_info *dev, match;
+ GSList *l;
+
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, bdaddr);
+ match.name_status = NAME_ANY;
+
+ /* ignore repeated entries */
+ l = g_slist_find_custom(*list, &match, (GCompareFunc) found_device_cmp);
+ if (l) {
+ /* device found, update the attributes */
+ dev = l->data;
+
+ if (rssi != 0)
+ dev->rssi = rssi;
+
+ /* Get remote name can be received while inquiring.
+ * Keep in mind that multiple inquiry result events can
+ * be received from the same remote device.
+ */
+ if (name_status != NAME_NOT_REQUIRED)
+ dev->name_status = name_status;
+
+ *list = g_slist_sort(*list, (GCompareFunc) dev_rssi_cmp);
+
+ return -EALREADY;
+ }
+
+ dev = g_new0(struct remote_dev_info, 1);
+
+ bacpy(&dev->bdaddr, bdaddr);
+ dev->rssi = rssi;
+ dev->name_status = name_status;
+
+ *list = g_slist_insert_sorted(*list, dev, (GCompareFunc) dev_rssi_cmp);
+
+ return 0;
+}
+
+static int found_device_remove(GSList **list, bdaddr_t *bdaddr)
+{
+ struct remote_dev_info *dev, match;
+ GSList *l;
+
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, bdaddr);
+
+ l = g_slist_find_custom(*list, &match, (GCompareFunc) found_device_cmp);
+ if (!l)
+ return -1;
+
+ dev = l->data;
+ *list = g_slist_remove(*list, dev);
+ g_free(dev);
+
+ return 0;
+}
+
+int active_conn_find_by_bdaddr(const void *data, const void *user_data)
+{
+ const struct active_conn_info *con = data;
+ const bdaddr_t *bdaddr = user_data;
+
+ return bacmp(&con->bdaddr, bdaddr);
+}
+
+static int active_conn_find_by_handle(const void *data, const void *user_data)
+{
+ const struct active_conn_info *dev = data;
+ const uint16_t *handle = user_data;
+
+ if (dev->handle == *handle)
+ return 0;
+
+ return -1;
+}
+
+static int active_conn_append(GSList **list, bdaddr_t *bdaddr,
+ uint16_t handle)
+{
+ struct active_conn_info *dev;
+
+ dev = g_new0(struct active_conn_info, 1);
+
+ bacpy(&dev->bdaddr, bdaddr);
+ dev->handle = handle;
+
+ *list = g_slist_append(*list, dev);
+ return 0;
+}
+
+DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)
+{
+ switch (status) {
+ case 0x00: /* success */
+ return dbus_message_new_method_return(msg);
+
+ case 0x04: /* page timeout */
+ case 0x08: /* connection timeout */
+ case 0x10: /* connection accept timeout */
+ case 0x22: /* LMP response timeout */
+ case 0x28: /* instant passed - is this a timeout? */
+ return dbus_message_new_error(msg,
+ ERROR_INTERFACE ".AuthenticationTimeout",
+ "Authentication Timeout");
+ case 0x17: /* too frequent pairing attempts */
+ return dbus_message_new_error(msg,
+ ERROR_INTERFACE ".RepeatedAttempts",
+ "Repeated Attempts");
+
+ case 0x06:
+ case 0x18: /* pairing not allowed (e.g. gw rejected attempt) */
+ return dbus_message_new_error(msg,
+ ERROR_INTERFACE ".AuthenticationRejected",
+ "Authentication Rejected");
+
+ case 0x07: /* memory capacity */
+ case 0x09: /* connection limit */
+ case 0x0a: /* synchronous connection limit */
+ case 0x0d: /* limited resources */
+ case 0x14: /* terminated due to low resources */
+ return dbus_message_new_error(msg,
+ ERROR_INTERFACE ".AuthenticationCanceled",
+ "Authentication Canceled");
+
+ case 0x05: /* authentication failure */
+ case 0x0E: /* rejected due to security reasons - is this auth failure? */
+ case 0x25: /* encryption mode not acceptable - is this auth failure? */
+ case 0x26: /* link key cannot be changed - is this auth failure? */
+ case 0x29: /* pairing with unit key unsupported - is this auth failure? */
+ case 0x2f: /* insufficient security - is this auth failure? */
+ default:
+ return dbus_message_new_error(msg,
+ ERROR_INTERFACE ".AuthenticationFailed",
+ "Authentication Failed");
+ }
+}
+
+static dbus_bool_t send_adapter_signal(DBusConnection *conn, int devid,
+ const char *name, int first, ...)
+{
+ va_list var_args;
+ dbus_bool_t ret;
+ char path[MAX_PATH_LENGTH];
+
+ snprintf(path, sizeof(path)-1, "%s/hci%d", BASE_PATH, devid);
+
+ va_start(var_args, first);
+ ret = g_dbus_emit_signal_valist(conn, path, ADAPTER_INTERFACE,
+ name, first, var_args);
+ va_end(var_args);
+
+ return ret;
+}
+
+static void adapter_mode_changed(struct adapter *adapter, uint8_t scan_enable)
+{
+ const char *mode;
+
+ adapter->scan_enable = scan_enable;
+
+ switch (scan_enable) {
+ case SCAN_DISABLED:
+ mode = "off";
+ adapter->mode = MODE_OFF;
+ break;
+ case SCAN_PAGE:
+ mode = "connectable";
+ adapter->mode = MODE_CONNECTABLE;
+ break;
+ case (SCAN_PAGE | SCAN_INQUIRY):
+
+ if (adapter->discov_timeout != 0)
+ adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000,
+ discov_timeout_handler, adapter);
+
+ if (adapter->mode == MODE_LIMITED) {
+ mode = "limited";
+ } else {
+ adapter->mode = MODE_DISCOVERABLE;
+ mode = "discoverable";
+ }
+ break;
+ case SCAN_INQUIRY:
+ /* Address the scenario where another app changed the scan mode */
+ if (adapter->discov_timeout != 0)
+ adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000,
+ discov_timeout_handler, adapter);
+ /* ignore, this event should not be sent*/
+ default:
+ /* ignore, reserved */
+ return;
+ }
+
+ g_dbus_emit_signal(connection, adapter->path, ADAPTER_INTERFACE,
+ "ModeChanged",
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental()) {
+ const char *ptr = adapter->path + ADAPTER_PATH_INDEX;
+ dbus_connection_emit_property_changed(connection, ptr,
+ ADAPTER_INTERFACE, "Mode",
+ DBUS_TYPE_STRING, &mode);
+ }
+}
+
+/*
+ * HCI D-Bus services
+ */
+static void reply_pending_requests(const char *path, struct adapter *adapter)
+{
+ if (!path || !adapter)
+ return;
+
+ /* pending bonding */
+ if (adapter->bonding) {
+ error_authentication_canceled(connection, adapter->bonding->msg);
+
+ remove_pending_device(adapter);
+
+ g_dbus_remove_watch(adapter->bonding->conn,
+ adapter->bonding->listener_id);
+
+ if (adapter->bonding->io_id)
+ g_source_remove(adapter->bonding->io_id);
+ g_io_channel_close(adapter->bonding->io);
+ bonding_request_free(adapter->bonding);
+ adapter->bonding = NULL;
+ }
+
+ /* If there is a pending reply for discovery cancel */
+ if (adapter->discovery_cancel) {
+ DBusMessage *reply;
+ reply = dbus_message_new_method_return(adapter->discovery_cancel);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ dbus_message_unref(adapter->discovery_cancel);
+ adapter->discovery_cancel = NULL;
+ }
+
+ if (adapter->discov_active) {
+ /* Send discovery completed signal if there isn't name
+ * to resolve */
+ if (hcid_dbus_use_experimental()) {
+ const char *ptr = path + ADAPTER_PATH_INDEX;
+
+ g_dbus_emit_signal(connection, ptr,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+
+ }
+
+ g_dbus_emit_signal(connection, path,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+
+ /* Cancel inquiry initiated by D-Bus client */
+ if (adapter->discov_requestor)
+ cancel_discovery(adapter);
+ }
+
+ if (adapter->pdiscov_active) {
+ /* Send periodic discovery stopped signal exit or stop
+ * the device */
+ g_dbus_emit_signal(connection, path,
+ ADAPTER_INTERFACE,
+ "PeriodicDiscoveryStopped",
+ DBUS_TYPE_INVALID);
+
+ /* Stop periodic inquiry initiated by D-Bus client */
+ if (adapter->pdiscov_requestor)
+ cancel_periodic_discovery(adapter);
+ }
+}
+
+static void do_unregister(gpointer data, gpointer user_data)
+{
+ DBusConnection *conn = user_data;
+ struct device *device = data;
+
+ device_remove(conn, device);
+}
+
+int unregister_adapter_path(const char *path)
+{
+ struct adapter *adapter;
+
+ info("Unregister path: %s", path);
+
+ __remove_servers(path);
+
+ adapter = manager_find_adapter_by_path(path);
+ if (!adapter)
+ goto unreg;
+
+ /* check pending requests */
+ reply_pending_requests(path, adapter);
+
+ cancel_passkey_agent_requests(adapter->passkey_agents, path, NULL);
+
+ release_passkey_agents(adapter, NULL);
+
+ if (adapter->agent) {
+ agent_destroy(adapter->agent, FALSE);
+ adapter->agent = NULL;
+ }
+
+ if (adapter->discov_requestor) {
+ g_dbus_remove_watch(connection, adapter->discov_listener);
+ adapter->discov_listener = 0;
+ g_free(adapter->discov_requestor);
+ adapter->discov_requestor = NULL;
+ }
+
+ if (adapter->pdiscov_requestor) {
+ g_dbus_remove_watch(connection, adapter->pdiscov_listener);
+ adapter->pdiscov_listener = 0;
+ g_free(adapter->pdiscov_requestor);
+ adapter->pdiscov_requestor = NULL;
+ }
+
+ if (adapter->found_devices) {
+ g_slist_foreach(adapter->found_devices,
+ (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+ }
+
+ if (adapter->oor_devices) {
+ g_slist_foreach(adapter->oor_devices,
+ (GFunc) free, NULL);
+ g_slist_free(adapter->oor_devices);
+ adapter->oor_devices = NULL;
+ }
+
+ if (adapter->auth_reqs) {
+ g_slist_foreach(adapter->auth_reqs,
+ (GFunc) g_free, NULL);
+ g_slist_free(adapter->auth_reqs);
+ adapter->auth_reqs = NULL;
+ }
+
+ if (adapter->active_conn) {
+ g_slist_foreach(adapter->active_conn,
+ (GFunc) free, NULL);
+ g_slist_free(adapter->active_conn);
+ adapter->active_conn = NULL;
+ }
+
+ /* Check if there is a pending RemoteDeviceDisconnect request */
+ if (adapter->pending_dc) {
+ error_no_such_adapter(adapter->pending_dc->conn,
+ adapter->pending_dc->msg);
+ g_source_remove(adapter->pending_dc->timeout_id);
+ dc_pending_timeout_cleanup(adapter);
+ }
+
+ if (adapter->devices) {
+ g_slist_foreach(adapter->devices, do_unregister,
+ connection);
+ g_slist_free(adapter->devices);
+ }
+
+ manager_remove_adapter(adapter);
+
+ g_free(adapter->path);
+ g_free(adapter);
+
+unreg:
+ if (!adapter_cleanup(connection, path)) {
+ error("Failed to unregister adapter interface on %s object",
+ path);
+ return -1;
+ }
+
+ if (!security_cleanup(connection, path)) {
+ error("Failed to unregister security interface on %s object",
+ path);
+ return -1;
+ }
+
+ if (hcid_dbus_use_experimental()) {
+ const char *ptr = path + ADAPTER_PATH_INDEX;
+
+ adapter_cleanup(connection, ptr);
+ }
+
+ return 0;
+}
+
+/*****************************************************************
+ *
+ * Section reserved to HCI commands confirmation handling and low
+ * level events(eg: device attached/dettached.
+ *
+ *****************************************************************/
+
+int hcid_dbus_register_device(uint16_t id)
+{
+ char path[MAX_PATH_LENGTH];
+ char *ptr = path + ADAPTER_PATH_INDEX;
+ struct adapter *adapter;
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
+
+ adapter = g_try_new0(struct adapter, 1);
+ if (!adapter) {
+ error("Failed to alloc memory to D-Bus path register data (%s)",
+ path);
+ return -1;
+ }
+
+ adapter->dev_id = id;
+ adapter->pdiscov_resolve_names = 1;
+
+ if (!adapter_init(connection, path, adapter)) {
+ error("Adapter interface init failed on path %s", path);
+ g_free(adapter);
+ return -1;
+ }
+
+ adapter->path = g_strdup(path);
+
+ if (!security_init(connection, path)) {
+ error("Security interface init failed on path %s", path);
+ goto failed;
+ }
+
+ __probe_servers(path);
+
+ manager_add_adapter(adapter);
+
+ return 0;
+
+failed:
+ if (hcid_dbus_use_experimental())
+ g_dbus_unregister_interface(connection, ptr, ADAPTER_INTERFACE);
+
+ g_dbus_unregister_interface(connection, path, ADAPTER_INTERFACE);
+
+ g_free(adapter->path);
+ g_free(adapter);
+
+ return -1;
+}
+
+int hcid_dbus_unregister_device(uint16_t id)
+{
+ char path[MAX_PATH_LENGTH];
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
+
+ return unregister_adapter_path(path);
+}
+
+static void create_stored_device_from_profiles(char *key, char *value,
+ void *user_data)
+{
+ struct adapter *adapter = user_data;
+ GSList *uuids = bt_string2list(value);
+ struct device *device;
+
+ device = device_create(connection, adapter, key);
+ if (device) {
+ device->temporary = FALSE;
+ adapter->devices = g_slist_append(adapter->devices, device);
+ device_probe_drivers(device, uuids);
+ g_slist_free(uuids);
+ }
+}
+
+static void create_stored_device_from_linkkeys(char *key, char *value,
+ void *user_data)
+{
+ struct adapter *adapter = user_data;
+ struct device *device;
+
+ if (g_slist_find_custom(adapter->devices,
+ key, (GCompareFunc) device_address_cmp))
+ return;
+
+ device = device_create(connection, adapter, key);
+ if (device) {
+ device->temporary = FALSE;
+ adapter->devices = g_slist_append(adapter->devices, device);
+ }
+}
+
+static void register_devices(bdaddr_t *src, struct adapter *adapter)
+{
+ char filename[PATH_MAX + 1];
+ char addr[18];
+
+ ba2str(src, addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "profiles");
+ textfile_foreach(filename, create_stored_device_from_profiles, adapter);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "linkkeys");
+ textfile_foreach(filename, create_stored_device_from_linkkeys, adapter);
+}
+
+int hcid_dbus_start_device(uint16_t id)
+{
+ char path[MAX_PATH_LENGTH];
+ char *ptr = path + ADAPTER_PATH_INDEX;
+ struct hci_dev_info di;
+ struct adapter* adapter;
+ struct hci_conn_list_req *cl = NULL;
+ struct hci_conn_info *ci;
+ const char *mode;
+ int i, err, dd = -1, ret = -1;
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
+
+ if (hci_devinfo(id, &di) < 0) {
+ error("Getting device info failed: hci%d", id);
+ return -1;
+ }
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ return -1;
+
+ adapter = manager_find_adapter_by_path(path);
+ if (!adapter) {
+ error("Getting %s path data failed!", path);
+ return -1;
+ }
+
+ if (hci_test_bit(HCI_INQUIRY, &di.flags))
+ adapter->discov_active = 1;
+ else
+ adapter->discov_active = 0;
+
+ adapter->up = 1;
+ adapter->discov_timeout = get_discoverable_timeout(id);
+ adapter->discov_type = DISCOVER_TYPE_NONE;
+
+ dd = hci_open_dev(id);
+ if (dd < 0)
+ goto failed;
+
+ adapter->scan_enable = get_startup_scan(id);
+ hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+ 1, &adapter->scan_enable);
+ /*
+ * Get the adapter Bluetooth address
+ */
+ err = get_device_address(adapter->dev_id, adapter->address,
+ sizeof(adapter->address));
+ if (err < 0)
+ goto failed;
+
+ err = get_device_class(adapter->dev_id, adapter->class);
+ if (err < 0)
+ goto failed;
+
+ adapter->mode = get_startup_mode(id);
+ if (adapter->mode == MODE_LIMITED)
+ set_limited_discoverable(dd, adapter->class, TRUE);
+
+ /*
+ * retrieve the active connections: address the scenario where
+ * the are active connections before the daemon've started
+ */
+
+ cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl));
+
+ cl->dev_id = id;
+ cl->conn_num = 10;
+ ci = cl->conn_info;
+
+ if (ioctl(dd, HCIGETCONNLIST, cl) < 0)
+ goto failed;
+
+ for (i = 0; i < cl->conn_num; i++, ci++)
+ active_conn_append(&adapter->active_conn,
+ &ci->bdaddr, ci->handle);
+
+ ret = 0;
+
+ mode = mode2str(adapter->mode);
+ g_dbus_emit_signal(connection, path, ADAPTER_INTERFACE,
+ "ModeChanged",
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental()) {
+ dbus_connection_emit_property_changed(connection, ptr,
+ ADAPTER_INTERFACE, "Mode",
+ DBUS_TYPE_STRING, &mode);
+ }
+
+ if (manager_get_default_adapter() < 0)
+ manager_set_default_adapter(id);
+
+ if (hcid_dbus_use_experimental())
+ register_devices(&di.bdaddr, adapter);
+
+failed:
+ if (dd >= 0)
+ hci_close_dev(dd);
+
+ g_free(cl);
+
+ return ret;
+}
+
+static void send_dc_signal(struct active_conn_info *dev, const char *path)
+{
+ char addr[18];
+ const char *paddr = addr;
+
+ ba2str(&dev->bdaddr, addr);
+
+ g_dbus_emit_signal(connection, path, ADAPTER_INTERFACE,
+ "RemoteDeviceDisconnected",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+}
+
+int hcid_dbus_stop_device(uint16_t id)
+{
+ char path[MAX_PATH_LENGTH];
+ struct adapter *adapter;
+ const char *mode = "off";
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
+
+ adapter = manager_find_adapter_by_path(path);
+ if (!adapter) {
+ error("Getting %s path data failed!", path);
+ return -1;
+ }
+
+ /* cancel pending timeout */
+ if (adapter->timeout_id) {
+ g_source_remove(adapter->timeout_id);
+ adapter->timeout_id = 0;
+ }
+
+ /* check pending requests */
+ reply_pending_requests(path, adapter);
+
+ cancel_passkey_agent_requests(adapter->passkey_agents, path, NULL);
+
+ release_passkey_agents(adapter, NULL);
+
+ if (adapter->discov_requestor) {
+ g_dbus_remove_watch(connection, adapter->discov_listener);
+ adapter->discov_listener = 0;
+ g_free(adapter->discov_requestor);
+ adapter->discov_requestor = NULL;
+ }
+
+ if (adapter->pdiscov_requestor) {
+ g_dbus_remove_watch(connection, adapter->pdiscov_listener);
+ adapter->pdiscov_listener = 0;
+ g_free(adapter->pdiscov_requestor);
+ adapter->pdiscov_requestor = NULL;
+ }
+
+ if (adapter->found_devices) {
+ g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+ }
+
+ if (adapter->oor_devices) {
+ g_slist_foreach(adapter->oor_devices, (GFunc) free, NULL);
+ g_slist_free(adapter->oor_devices);
+ adapter->oor_devices = NULL;
+ }
+
+ if (adapter->auth_reqs) {
+ g_slist_foreach(adapter->auth_reqs, (GFunc) g_free, NULL);
+ g_slist_free(adapter->auth_reqs);
+ adapter->auth_reqs = NULL;
+ }
+
+ if (adapter->active_conn) {
+ g_slist_foreach(adapter->active_conn, (GFunc) send_dc_signal, path);
+ g_slist_foreach(adapter->active_conn, (GFunc) g_free, NULL);
+ g_slist_free(adapter->active_conn);
+ adapter->active_conn = NULL;
+ }
+
+ send_adapter_signal(connection, adapter->dev_id, "ModeChanged",
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental()) {
+ const char *ptr = path + ADAPTER_PATH_INDEX;
+ dbus_connection_emit_property_changed(connection, ptr,
+ ADAPTER_INTERFACE, "Mode",
+ DBUS_TYPE_STRING, &mode);
+ }
+
+ adapter->up = 0;
+ adapter->scan_enable = SCAN_DISABLED;
+ adapter->mode = MODE_OFF;
+ adapter->discov_active = 0;
+ adapter->pdiscov_active = 0;
+ adapter->pinq_idle = 0;
+ adapter->discov_type = DISCOVER_TYPE_NONE;
+
+ return 0;
+}
+
+static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,
+ struct device *device)
+{
+ struct adapter *adapter = device->adapter;
+ pin_code_reply_cp pr;
+ bdaddr_t sba, dba;
+ size_t len;
+ int dev;
+ struct pending_auth_info *auth;
+
+ /* No need to reply anything if the authentication already failed */
+ if (adapter->bonding && adapter->bonding->hci_status)
+ return;
+
+ dev = hci_open_dev(adapter->dev_id);
+ if (dev < 0) {
+ error("hci_open_dev(%d): %s (%d)", adapter->dev_id,
+ strerror(errno), errno);
+ return;
+ }
+
+ str2ba(adapter->address, &sba);
+ str2ba(device->address, &dba);
+
+ auth = adapter_find_auth_request(adapter, &dba);
+
+ if (err) {
+ hci_send_cmd(dev, OGF_LINK_CTL,
+ OCF_PIN_CODE_NEG_REPLY, 6, &dba);
+ goto done;
+ }
+
+ len = strlen(pincode);
+
+ set_pin_length(&sba, len);
+
+ memset(&pr, 0, sizeof(pr));
+ bacpy(&pr.bdaddr, &dba);
+ memcpy(pr.pin_code, pincode, len);
+ pr.pin_len = len;
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr);
+
+done:
+ if (auth) {
+ auth->replied = TRUE;
+ auth->agent = NULL;
+ }
+ hci_close_dev(dev);
+}
+
+int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci)
+{
+ char addr[18];
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ int ret;
+
+ adapter = manager_find_adapter(sba);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ if (!hcid_dbus_use_experimental())
+ goto old_fallback;
+
+ ba2str(&ci->bdaddr, addr);
+
+ device = adapter_find_device(adapter, addr);
+ agent = device && device->agent ? device->agent : adapter->agent;
+ if (!agent)
+ goto old_fallback;
+
+ if (!device) {
+ device = adapter_create_device(connection, adapter, addr);
+ if (!device)
+ return -ENODEV;
+ }
+
+ ret = agent_request_pincode(agent, device,
+ (agent_pincode_cb) pincode_cb,
+ device);
+ if (ret == 0) {
+ struct pending_auth_info *auth;
+ auth = adapter_new_auth_request(adapter, &ci->bdaddr,
+ AUTH_TYPE_PINCODE);
+ auth->agent = agent;
+ }
+
+
+ return ret;
+
+old_fallback:
+ ret = handle_passkey_request_old(connection, dev, adapter, sba,
+ &ci->bdaddr);
+ if (ret == 0)
+ adapter_new_auth_request(adapter, &ci->bdaddr,
+ AUTH_TYPE_PINCODE);
+ return ret;
+}
+
+static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)
+{
+ struct device *device = user_data;
+ struct adapter *adapter = device->adapter;
+ user_confirm_reply_cp cp;
+ int dd;
+ struct pending_auth_info *auth;
+
+ /* No need to reply anything if the authentication already failed */
+ if (adapter->bonding && adapter->bonding->hci_status)
+ return;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", adapter->dev_id);
+ return;
+ }
+
+ memset(&cp, 0, sizeof(cp));
+ str2ba(device->address, &cp.bdaddr);
+
+ auth = adapter_find_auth_request(adapter, &cp.bdaddr);
+
+ if (err)
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
+ USER_CONFIRM_REPLY_CP_SIZE, &cp);
+ else
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY,
+ USER_CONFIRM_REPLY_CP_SIZE, &cp);
+
+ if (auth) {
+ auth->replied = TRUE;
+ auth->agent = FALSE;
+ }
+
+ hci_close_dev(dd);
+}
+
+static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
+ void *user_data)
+{
+ struct device *device = user_data;
+ struct adapter *adapter = device->adapter;
+ user_passkey_reply_cp cp;
+ bdaddr_t dba;
+ int dd;
+ struct pending_auth_info *auth;
+
+ /* No need to reply anything if the authentication already failed */
+ if (adapter->bonding && adapter->bonding->hci_status)
+ return;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", adapter->dev_id);
+ return;
+ }
+
+ str2ba(device->address, &dba);
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, &dba);
+ cp.passkey = passkey;
+
+ auth = adapter_find_auth_request(adapter, &dba);
+
+ if (err)
+ hci_send_cmd(dd, OGF_LINK_CTL,
+ OCF_USER_PASSKEY_NEG_REPLY, 6, &dba);
+ else
+ hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_PASSKEY_REPLY,
+ USER_PASSKEY_REPLY_CP_SIZE, &cp);
+
+ if (auth) {
+ auth->replied = TRUE;
+ auth->agent = NULL;
+ }
+
+ hci_close_dev(dd);
+}
+
+static int get_auth_requirements(bdaddr_t *local, bdaddr_t *remote,
+ uint8_t *auth)
+{
+ struct hci_auth_info_req req;
+ char addr[18];
+ int err, dd, dev_id;
+
+ ba2str(local, addr);
+
+ dev_id = hci_devid(addr);
+ if (dev_id < 0)
+ return dev_id;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0)
+ return dd;
+
+ memset(&req, 0, sizeof(req));
+ bacpy(&req.bdaddr, remote);
+
+ err = ioctl(dd, HCIGETAUTHINFO, (unsigned long) &req);
+ if (err < 0) {
+ debug("HCIGETAUTHINFO failed: %s (%d)",
+ strerror(errno), errno);
+ hci_close_dev(dd);
+ return err;
+ }
+
+ hci_close_dev(dd);
+
+ if (auth)
+ *auth = req.type;
+
+ return 0;
+}
+
+int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
+{
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ char addr[18];
+ uint8_t type;
+ struct pending_auth_info *auth;
+
+ adapter = manager_find_adapter(sba);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ if (get_auth_requirements(sba, dba, &type) < 0) {
+ int dd;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", adapter->dev_id);
+ return -1;
+ }
+
+ hci_send_cmd(dd, OGF_LINK_CTL,
+ OCF_USER_CONFIRM_NEG_REPLY, 6, dba);
+
+ hci_close_dev(dd);
+
+ return 0;
+ }
+
+ ba2str(dba, addr);
+
+ device = adapter_get_device(connection, adapter, addr);
+ if (!device) {
+ error("Device creation failed");
+ return -1;
+ }
+
+ /* If no MITM protection required, auto-accept */
+ if (!(device->auth & 0x01) && !(type & 0x01)) {
+ int dd;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("Unable to open hci%d", adapter->dev_id);
+ return -1;
+ }
+
+ hci_send_cmd(dd, OGF_LINK_CTL,
+ OCF_USER_CONFIRM_REPLY, 6, dba);
+
+ hci_close_dev(dd);
+
+ return 0;
+ }
+
+ if (device->agent)
+ agent = device->agent;
+ else
+ agent = adapter->agent;
+
+ if (!agent) {
+ error("No agent available for user confirm request");
+ return -1;
+ }
+
+ if (agent_request_confirmation(agent, device, passkey,
+ confirm_cb, device) < 0) {
+ error("Requesting passkey failed");
+ return -1;
+ }
+
+ auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_CONFIRM);
+ auth->agent = agent;
+
+ return 0;
+}
+
+int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
+{
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ char addr[18];
+ struct pending_auth_info *auth;
+
+ adapter = manager_find_adapter(sba);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ ba2str(dba, addr);
+
+ device = adapter_get_device(connection, adapter, addr);
+ if (device && device->agent)
+ agent = device->agent;
+ else
+ agent = adapter->agent;
+
+ if (!agent) {
+ error("No agent available for user confirm request");
+ return -1;
+ }
+
+ if (agent_request_passkey(agent, device, passkey_cb, device) < 0) {
+ error("Requesting passkey failed");
+ return -1;
+ }
+
+ auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_PASSKEY);
+ auth->agent = agent;
+
+ return 0;
+}
+
+int hcid_dbus_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
+{
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ char addr[18];
+ struct pending_auth_info *auth;
+
+ adapter = manager_find_adapter(sba);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ ba2str(dba, addr);
+
+ device = adapter_get_device(connection, adapter, addr);
+ if (device && device->agent)
+ agent = device->agent;
+ else
+ agent = adapter->agent;
+
+ if (!agent) {
+ error("No agent available for user confirm request");
+ return -1;
+ }
+
+ if (agent_display_passkey(agent, device, passkey) < 0) {
+ error("Displaying passkey failed");
+ return -1;
+ }
+
+ auth = adapter_new_auth_request(adapter, dba, AUTH_TYPE_NOTIFY);
+ auth->agent = agent;
+
+ return 0;
+}
+
+void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer,
+ uint8_t status)
+{
+ struct adapter *adapter;
+ char peer_addr[18];
+ const char *paddr = peer_addr;
+ DBusMessage *reply;
+ struct device *device;
+ struct bonding_request_info *bonding;
+ gboolean paired = TRUE;
+ struct pending_auth_info *auth;
+
+ debug("hcid_dbus_bonding_process_complete: status=%02x", status);
+
+ ba2str(peer, peer_addr);
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("Unable to find matching adapter");
+ return;
+ }
+
+ if (status) {
+ if (adapter->bonding)
+ adapter->bonding->hci_status = status;
+ cancel_passkey_agent_requests(adapter->passkey_agents,
+ adapter->path, peer);
+ }
+
+ auth = adapter_find_auth_request(adapter, peer);
+ if (!auth) {
+ debug("hcid_dbus_bonding_process_complete: no pending auth request");
+ goto proceed;
+ }
+
+ if (auth->agent)
+ agent_cancel(auth->agent);
+
+ adapter_remove_auth_request(adapter, peer);
+
+ if (status)
+ goto proceed;
+
+ send_adapter_signal(connection, adapter->dev_id, "BondingCreated",
+ DBUS_TYPE_STRING, &paddr, DBUS_TYPE_INVALID);
+
+ device = adapter_get_device(connection, adapter, paddr);
+ if (device) {
+ char *ptr = adapter->path + ADAPTER_PATH_INDEX;
+
+ debug("hcid_dbus_bonding_process_complete: removing temporary flag");
+
+ device->temporary = FALSE;
+
+ g_dbus_emit_signal(connection, ptr,
+ ADAPTER_INTERFACE,
+ "DeviceCreated",
+ DBUS_TYPE_OBJECT_PATH,
+ &device->path,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_emit_property_changed(connection, device->path,
+ DEVICE_INTERFACE, "Paired",
+ DBUS_TYPE_BOOLEAN, &paired);
+ }
+
+proceed:
+
+ release_passkey_agents(adapter, peer);
+
+ bonding = adapter->bonding;
+ if (!bonding || bacmp(&bonding->bdaddr, peer))
+ return; /* skip: no bonding req pending */
+
+ if (bonding->cancel) {
+ /* reply authentication canceled */
+ error_authentication_canceled(connection, bonding->msg);
+ goto cleanup;
+ }
+
+ /* reply authentication success or an error */
+ if (dbus_message_is_method_call(bonding->msg, ADAPTER_INTERFACE,
+ "CreateBonding")) {
+ reply = new_authentication_return(bonding->msg, status);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ } else if ((device = adapter_find_device(adapter, paddr))) {
+ if (status) {
+ reply = new_authentication_return(bonding->msg, status);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ } else {
+ device->temporary = FALSE;
+ device_browse(device, bonding->conn,
+ bonding->msg, NULL);
+ }
+ }
+
+cleanup:
+ g_dbus_remove_watch(connection, adapter->bonding->listener_id);
+
+ if (adapter->bonding->io_id)
+ g_source_remove(adapter->bonding->io_id);
+ g_io_channel_close(adapter->bonding->io);
+ bonding_request_free(adapter->bonding);
+ adapter->bonding = NULL;
+}
+
+void hcid_dbus_inquiry_start(bdaddr_t *local)
+{
+ struct adapter *adapter;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("Unable to find matching adapter");
+ return;
+ }
+
+ adapter->discov_active = 1;
+ /*
+ * Cancel pending remote name request and clean the device list
+ * when inquiry is supported in periodic inquiry idle state.
+ */
+ if (adapter->pdiscov_active)
+ pending_remote_name_cancel(adapter);
+
+ /* Disable name resolution for non D-Bus clients */
+ if (!adapter->discov_requestor)
+ adapter->discov_type &= ~RESOLVE_NAME;
+
+ if (hcid_dbus_use_experimental())
+ dbus_connection_emit_property_changed(connection,
+ adapter->path + ADAPTER_PATH_INDEX,
+ ADAPTER_INTERFACE, "PeriodicDiscovery",
+ DBUS_TYPE_BOOLEAN, &adapter->discov_active);
+
+ send_adapter_signal(connection, adapter->dev_id, "DiscoveryStarted",
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental())
+ g_dbus_emit_signal(connection,
+ adapter->path + ADAPTER_PATH_INDEX,
+ ADAPTER_INTERFACE,
+ "DiscoveryStarted",
+ DBUS_TYPE_INVALID);
+}
+
+int found_device_req_name(struct adapter *adapter)
+{
+ struct hci_request rq;
+ evt_cmd_status rp;
+ remote_name_req_cp cp;
+ struct remote_dev_info match;
+ GSList *l;
+ int dd, req_sent = 0;
+
+ /* get the next remote address */
+ if (!adapter->found_devices)
+ return -ENODATA;
+
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, BDADDR_ANY);
+ match.name_status = NAME_REQUIRED;
+
+ l = g_slist_find_custom(adapter->found_devices, &match,
+ (GCompareFunc) found_device_cmp);
+ if (!l)
+ return -ENODATA;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0)
+ return -errno;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_REMOTE_NAME_REQ;
+ rq.cparam = &cp;
+ rq.clen = REMOTE_NAME_REQ_CP_SIZE;
+ rq.rparam = &rp;
+ rq.rlen = EVT_CMD_STATUS_SIZE;
+ rq.event = EVT_CMD_STATUS;
+
+ /* send at least one request or return failed if the list is empty */
+ do {
+ struct remote_dev_info *dev = l->data;
+ char peer_addr[18];
+ const char *signal = NULL, *paddr = peer_addr;
+
+ /* flag to indicate the current remote name requested */
+ dev->name_status = NAME_REQUESTED;
+
+ memset(&rp, 0, sizeof(rp));
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, &dev->bdaddr);
+ cp.pscan_rep_mode = 0x02;
+
+ ba2str(&dev->bdaddr, peer_addr);
+
+ if (hci_send_req(dd, &rq, 500) < 0) {
+ error("Unable to send the HCI remote name request: %s (%d)",
+ strerror(errno), errno);
+ signal = "RemoteNameFailed";
+ }
+
+ if (rp.status) {
+ error("Remote name request failed with status 0x%02x",
+ rp.status);
+ signal = "RemoteNameFailed";
+ }
+
+ if (!signal) {
+ req_sent = 1;
+ /* if we are in discovery, inform application of getting name */
+ if (adapter->discov_type & (STD_INQUIRY | PERIODIC_INQUIRY))
+ signal = "RemoteNameRequested";
+ }
+
+ if (signal)
+ send_adapter_signal(connection, adapter->dev_id, signal,
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+
+ if (req_sent)
+ break;
+
+ /* if failed, request the next element */
+ /* remove the element from the list */
+ adapter->found_devices = g_slist_remove(adapter->found_devices, dev);
+ g_free(dev);
+
+ /* get the next element */
+ l = g_slist_find_custom(adapter->found_devices, &match,
+ (GCompareFunc) found_device_cmp);
+
+ } while (l);
+
+ hci_close_dev(dd);
+
+ if (!req_sent)
+ return -ENODATA;
+
+ return 0;
+}
+
+static void send_out_of_range(const char *path, GSList *l)
+{
+ while (l) {
+ const char *peer_addr = l->data;
+
+ g_dbus_emit_signal(connection, path,
+ ADAPTER_INTERFACE,
+ "RemoteDeviceDisappeared",
+ DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental()) {
+ const char *ptr = path + ADAPTER_PATH_INDEX;
+ g_dbus_emit_signal(connection, ptr,
+ ADAPTER_INTERFACE,
+ "DeviceDisappeared",
+ DBUS_TYPE_STRING,
+ &peer_addr,
+ DBUS_TYPE_INVALID);
+ }
+
+ l = l->next;
+ }
+}
+
+void hcid_dbus_inquiry_complete(bdaddr_t *local)
+{
+ struct adapter *adapter;
+ struct remote_dev_info *dev;
+ bdaddr_t tmp;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("Unable to find matching adapter");
+ return;
+ }
+
+ /* Out of range verification */
+ if (adapter->pdiscov_active && !adapter->discov_active) {
+ GSList *l;
+
+ send_out_of_range(adapter->path, adapter->oor_devices);
+
+ g_slist_foreach(adapter->oor_devices, (GFunc) free, NULL);
+ g_slist_free(adapter->oor_devices);
+ adapter->oor_devices = NULL;
+
+ l = adapter->found_devices;
+ while (l) {
+ dev = l->data;
+ baswap(&tmp, &dev->bdaddr);
+ adapter->oor_devices = g_slist_append(adapter->oor_devices,
+ batostr(&tmp));
+ l = l->next;
+ }
+ }
+
+ adapter->pinq_idle = 1;
+
+ /*
+ * Enable resolution again: standard inquiry can be
+ * received in the periodic inquiry idle state.
+ */
+ if (adapter->pdiscov_requestor && adapter->pdiscov_resolve_names)
+ adapter->discov_type |= RESOLVE_NAME;
+
+ /*
+ * The following scenarios can happen:
+ * 1. standard inquiry: always send discovery completed signal
+ * 2. standard inquiry + name resolving: send discovery completed
+ * after name resolving
+ * 3. periodic inquiry: skip discovery completed signal
+ * 4. periodic inquiry + standard inquiry: always send discovery
+ * completed signal
+ *
+ * Keep in mind that non D-Bus requests can arrive.
+ */
+
+ if (!found_device_req_name(adapter))
+ return; /* skip - there is name to resolve */
+
+ if (adapter->discov_active) {
+ if (hcid_dbus_use_experimental()) {
+ const char *ptr = adapter->path + ADAPTER_PATH_INDEX;
+ g_dbus_emit_signal(connection, ptr,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+
+ }
+
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+ adapter->discov_active = 0;
+ }
+
+ /* free discovered devices list */
+ g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+
+ if (adapter->discov_requestor) {
+ g_dbus_remove_watch(connection, adapter->discov_listener);
+ adapter->discov_listener = 0;
+ g_free(adapter->discov_requestor);
+ adapter->discov_requestor = NULL;
+
+ /* If there is a pending reply for discovery cancel */
+ if (adapter->discovery_cancel) {
+ DBusMessage *reply;
+ reply = dbus_message_new_method_return(adapter->discovery_cancel);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ dbus_message_unref(adapter->discovery_cancel);
+ adapter->discovery_cancel = NULL;
+ }
+
+ /* reset the discover type for standard inquiry only */
+ adapter->discov_type &= ~STD_INQUIRY;
+ }
+}
+
+void hcid_dbus_periodic_inquiry_start(bdaddr_t *local, uint8_t status)
+{
+ struct adapter *adapter;
+
+ /* Don't send the signal if the cmd failed */
+ if (status)
+ return;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ adapter->pdiscov_active = 1;
+
+ /* Disable name resolution for non D-Bus clients */
+ if (!adapter->pdiscov_requestor)
+ adapter->discov_type &= ~RESOLVE_NAME;
+
+ if (hcid_dbus_use_experimental())
+ dbus_connection_emit_property_changed(connection,
+ adapter->path + ADAPTER_PATH_INDEX,
+ ADAPTER_INTERFACE,
+ "PeriodicDiscovery",
+ DBUS_TYPE_BOOLEAN,
+ &adapter->pdiscov_active);
+
+ g_dbus_emit_signal(connection, adapter->path, ADAPTER_INTERFACE,
+ "PeriodicDiscoveryStarted",
+ DBUS_TYPE_INVALID);
+}
+
+void hcid_dbus_periodic_inquiry_exit(bdaddr_t *local, uint8_t status)
+{
+ struct adapter *adapter;
+ char *ptr;
+
+ /* Don't send the signal if the cmd failed */
+ if (status)
+ return;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ ptr = adapter->path + ADAPTER_PATH_INDEX;
+
+ /* reset the discover type to be able to handle D-Bus and non D-Bus
+ * requests */
+ adapter->pdiscov_active = 0;
+ adapter->discov_type &= ~(PERIODIC_INQUIRY | RESOLVE_NAME);
+
+ /* free discovered devices list */
+ g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+
+ /* free out of range devices list */
+ g_slist_foreach(adapter->oor_devices, (GFunc) free, NULL);
+ g_slist_free(adapter->oor_devices);
+ adapter->oor_devices = NULL;
+
+ if (adapter->pdiscov_requestor) {
+ g_dbus_remove_watch(connection, adapter->pdiscov_listener);
+ adapter->pdiscov_listener = 0;
+ g_free(adapter->pdiscov_requestor);
+ adapter->pdiscov_requestor = NULL;
+ }
+
+ /* workaround: inquiry completed is not sent when exiting from
+ * periodic inquiry */
+ if (adapter->discov_active) {
+ if (hcid_dbus_use_experimental())
+ g_dbus_emit_signal(connection, ptr,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+ adapter->discov_active = 0;
+ }
+
+ /* Send discovery completed signal if there isn't name to resolve */
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "PeriodicDiscoveryStopped",
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental())
+ dbus_connection_emit_property_changed(connection, ptr,
+ ADAPTER_INTERFACE,
+ "PeriodicDiscovery",
+ DBUS_TYPE_BOOLEAN,
+ &adapter->discov_active);
+}
+
+static char *extract_eir_name(uint8_t *data, uint8_t *type)
+{
+ if (!data || !type)
+ return NULL;
+
+ if (data[0] == 0)
+ return NULL;
+
+ *type = data[1];
+
+ switch (*type) {
+ case 0x08:
+ case 0x09:
+ return strndup((char *) (data + 2), data[0] - 1);
+ }
+
+ return NULL;
+}
+
+static void append_dict_valist(DBusMessageIter *iter,
+ const char *first_key,
+ va_list var_args)
+{
+ DBusMessageIter dict;
+ const char *key;
+ int type;
+ void *val;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ key = first_key;
+ while (key) {
+ type = va_arg(var_args, int);
+ val = va_arg(var_args, void *);
+ dbus_message_iter_append_dict_entry(&dict, key, type, val);
+ key = va_arg(var_args, char *);
+ }
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+static void emit_device_found(const char *path, const char *address,
+ const char *first_key, ...)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ va_list var_args;
+
+ signal = dbus_message_new_signal(path, ADAPTER_INTERFACE,
+ "DeviceFound");
+ if (!signal) {
+ error("Unable to allocate new %s.DeviceFound signal",
+ ADAPTER_INTERFACE);
+ return;
+ }
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &address);
+
+ va_start(var_args, first_key);
+ append_dict_valist(&iter, first_key, var_args);
+ va_end(var_args);
+
+ dbus_connection_send(connection, signal, NULL);
+
+ dbus_message_unref(signal);
+}
+
+void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
+ int8_t rssi, uint8_t *data)
+{
+ char filename[PATH_MAX + 1];
+ struct adapter *adapter;
+ GSList *l;
+ char local_addr[18], peer_addr[18], *name, *tmp_name;
+ const char *paddr = peer_addr;
+ struct remote_dev_info match;
+ dbus_int16_t tmp_rssi = rssi;
+ uint8_t name_type = 0x00;
+ name_status_t name_status;
+
+ ba2str(local, local_addr);
+ ba2str(peer, peer_addr);
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ write_remote_class(local, peer, class);
+
+ if (data)
+ write_remote_eir(local, peer, data);
+
+ /*
+ * workaround to identify situation when the daemon started and
+ * a standard inquiry or periodic inquiry was already running
+ */
+ if (!adapter->discov_active && !adapter->pdiscov_active)
+ adapter->pdiscov_active = 1;
+
+ /* reset the idle flag when the inquiry complete event arrives */
+ if (adapter->pdiscov_active) {
+ adapter->pinq_idle = 0;
+
+ /* Out of range list update */
+ l = g_slist_find_custom(adapter->oor_devices, peer_addr,
+ (GCompareFunc) strcmp);
+ if (l) {
+ char *dev = l->data;
+ adapter->oor_devices = g_slist_remove(adapter->oor_devices,
+ dev);
+ g_free(dev);
+ }
+ }
+
+ /* send the device found signal */
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "RemoteDeviceFound",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_UINT32, &class,
+ DBUS_TYPE_INT16, &tmp_rssi,
+ DBUS_TYPE_INVALID);
+
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, peer);
+ match.name_status = NAME_SENT;
+ /* if found: don't send the name again */
+ l = g_slist_find_custom(adapter->found_devices, &match,
+ (GCompareFunc) found_device_cmp);
+ if (l)
+ return;
+
+ /* the inquiry result can be triggered by NON D-Bus client */
+ if (adapter->discov_type & RESOLVE_NAME)
+ name_status = NAME_REQUIRED;
+ else
+ name_status = NAME_NOT_REQUIRED;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, local_addr, "names");
+ name = textfile_get(filename, peer_addr);
+
+ tmp_name = extract_eir_name(data, &name_type);
+ if (tmp_name) {
+ if (name_type == 0x09) {
+ write_device_name(local, peer, tmp_name);
+ name_status = NAME_NOT_REQUIRED;
+
+ if (name)
+ g_free(name);
+
+ name = tmp_name;
+ } else {
+ if (name)
+ free(tmp_name);
+ else
+ name = tmp_name;
+ }
+ }
+
+ if (name) {
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "RemoteNameUpdated",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ if (name_type != 0x08)
+ name_status = NAME_SENT;
+
+ if (hcid_dbus_use_experimental()) {
+ emit_device_found(adapter->path + ADAPTER_PATH_INDEX,
+ paddr,
+ "Address", DBUS_TYPE_STRING, &paddr,
+ "Class", DBUS_TYPE_UINT32, &class,
+ "RSSI", DBUS_TYPE_INT16, &tmp_rssi,
+ "Name", DBUS_TYPE_STRING, &name,
+ NULL);
+ }
+
+ g_free(name);
+ } else if (hcid_dbus_use_experimental()) {
+ emit_device_found(adapter->path + ADAPTER_PATH_INDEX,
+ paddr,
+ "Address", DBUS_TYPE_STRING, &paddr,
+ "Class", DBUS_TYPE_UINT32, &class,
+ "RSSI", DBUS_TYPE_INT16, &tmp_rssi,
+ NULL);
+ }
+
+ /* add in the list to track name sent/pending */
+ found_device_add(&adapter->found_devices, peer, rssi, name_status);
+}
+
+void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
+{
+ char peer_addr[18];
+ const char *paddr = peer_addr;
+ uint32_t old_class = 0;
+ struct adapter *adapter;
+
+ read_remote_class(local, peer, &old_class);
+
+ if (old_class == class)
+ return;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ ba2str(peer, peer_addr);
+
+ send_adapter_signal(connection, adapter->dev_id,
+ "RemoteClassUpdated",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_UINT32, &class,
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental()) {
+ GSList *l;
+ struct device *device;
+
+ l = g_slist_find_custom(adapter->devices, paddr,
+ (GCompareFunc) device_address_cmp);
+ if (!l)
+ return;
+
+ device = l->data;
+ dbus_connection_emit_property_changed(connection,
+ device->path, DEVICE_INTERFACE,
+ "Class", DBUS_TYPE_UINT32, &class);
+ }
+}
+
+void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status,
+ char *name)
+{
+ struct adapter *adapter;
+ char peer_addr[18];
+ const char *paddr = peer_addr;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ ba2str(peer, peer_addr);
+
+ if (status)
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "RemoteNameFailed",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+ else {
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "RemoteNameUpdated",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental()) {
+ struct device *device;
+
+ device = adapter_find_device(adapter, paddr);
+ if (device) {
+ dbus_connection_emit_property_changed(connection,
+ device->path, DEVICE_INTERFACE,
+ "Name", DBUS_TYPE_STRING, &name);
+ }
+ }
+ }
+
+ /* remove from remote name request list */
+ found_device_remove(&adapter->found_devices, peer);
+
+ /* check if there is more devices to request names */
+ if (!found_device_req_name(adapter))
+ return; /* skip if a new request has been sent */
+
+ /* free discovered devices list */
+ g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+
+ /* The discovery completed signal must be sent only for discover
+ * devices request WITH name resolving */
+ if (adapter->discov_requestor) {
+ g_dbus_remove_watch(connection, adapter->discov_listener);
+ adapter->discov_listener = 0;
+ g_free(adapter->discov_requestor);
+ adapter->discov_requestor = NULL;
+
+ /* If there is a pending reply for discovery cancel */
+ if (adapter->discovery_cancel) {
+ DBusMessage *reply;
+ reply = dbus_message_new_method_return(adapter->discovery_cancel);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ dbus_message_unref(adapter->discovery_cancel);
+ adapter->discovery_cancel = NULL;
+ }
+
+ /* Disable name resolution for non D-Bus clients */
+ if (!adapter->pdiscov_requestor)
+ adapter->discov_type &= ~RESOLVE_NAME;
+ }
+
+ if (adapter->discov_active) {
+ if (hcid_dbus_use_experimental())
+ g_dbus_emit_signal(connection,
+ adapter->path + ADAPTER_PATH_INDEX,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "DiscoveryCompleted",
+ DBUS_TYPE_INVALID);
+ adapter->discov_active = 0;
+ }
+}
+
+void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle,
+ bdaddr_t *peer)
+{
+ char peer_addr[18];
+ const char *paddr = peer_addr;
+ struct adapter *adapter;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ ba2str(peer, peer_addr);
+
+ if (status) {
+ struct pending_auth_info *auth;
+
+ cancel_passkey_agent_requests(adapter->passkey_agents,
+ adapter->path, peer);
+ release_passkey_agents(adapter, peer);
+
+ auth = adapter_find_auth_request(adapter, peer);
+ if (auth && auth->agent)
+ agent_cancel(auth->agent);
+
+ adapter_remove_auth_request(adapter, peer);
+
+ if (adapter->bonding)
+ adapter->bonding->hci_status = status;
+ } else {
+ /* Send the remote device connected signal */
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "RemoteDeviceConnected",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+
+ if (hcid_dbus_use_experimental()) {
+ struct device *device;
+ gboolean connected = TRUE;
+
+ device = adapter_find_device(adapter, paddr);
+ if (device) {
+ dbus_connection_emit_property_changed(connection,
+ device->path, DEVICE_INTERFACE,
+ "Connected", DBUS_TYPE_BOOLEAN,
+ &connected);
+ }
+ }
+
+ /* add in the active connetions list */
+ active_conn_append(&adapter->active_conn, peer, handle);
+ }
+}
+
+void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status,
+ uint16_t handle, uint8_t reason)
+{
+ DBusMessage *reply;
+ char peer_addr[18];
+ const char *paddr = peer_addr;
+ struct adapter *adapter;
+ struct device *device;
+ struct active_conn_info *dev;
+ GSList *l;
+ gboolean connected = FALSE;
+ struct pending_auth_info *auth;
+
+ if (status) {
+ error("Disconnection failed: 0x%02x", status);
+ return;
+ }
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ l = g_slist_find_custom(adapter->active_conn, &handle,
+ active_conn_find_by_handle);
+
+ if (!l)
+ return;
+
+ dev = l->data;
+
+ ba2str(&dev->bdaddr, peer_addr);
+
+ /* clean pending HCI cmds */
+ hci_req_queue_remove(adapter->dev_id, &dev->bdaddr);
+
+ /* Cancel D-Bus/non D-Bus requests */
+ cancel_passkey_agent_requests(adapter->passkey_agents, adapter->path,
+ &dev->bdaddr);
+ release_passkey_agents(adapter, &dev->bdaddr);
+
+ auth = adapter_find_auth_request(adapter, &dev->bdaddr);
+ if (auth && auth->agent)
+ agent_cancel(auth->agent);
+
+ adapter_remove_auth_request(adapter, &dev->bdaddr);
+
+ /* Check if there is a pending CreateBonding request */
+ if (adapter->bonding && (bacmp(&adapter->bonding->bdaddr, &dev->bdaddr) == 0)) {
+ if (adapter->bonding->cancel) {
+ /* reply authentication canceled */
+ error_authentication_canceled(connection,
+ adapter->bonding->msg);
+ } else {
+ reply = new_authentication_return(adapter->bonding->msg,
+ HCI_AUTHENTICATION_FAILURE);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+ g_dbus_remove_watch(adapter->bonding->conn,
+ adapter->bonding->listener_id);
+
+ if (adapter->bonding->io_id)
+ g_source_remove(adapter->bonding->io_id);
+ g_io_channel_close(adapter->bonding->io);
+ bonding_request_free(adapter->bonding);
+ adapter->bonding = NULL;
+ }
+
+ /* Check if there is a pending RemoteDeviceDisconnect request */
+ if (adapter->pending_dc) {
+ reply = dbus_message_new_method_return(adapter->pending_dc->msg);
+ if (reply) {
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ } else
+ error("Failed to allocate disconnect reply");
+
+ g_source_remove(adapter->pending_dc->timeout_id);
+ dc_pending_timeout_cleanup(adapter);
+ }
+
+ /* Send the remote device disconnected signal */
+ g_dbus_emit_signal(connection, adapter->path,
+ ADAPTER_INTERFACE,
+ "RemoteDeviceDisconnected",
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+
+ adapter->active_conn = g_slist_remove(adapter->active_conn, dev);
+ g_free(dev);
+
+ device = adapter_find_device(adapter, paddr);
+ if (device) {
+ dbus_connection_emit_property_changed(connection,
+ device->path, DEVICE_INTERFACE,
+ "Connected", DBUS_TYPE_BOOLEAN,
+ &connected);
+ if (device->temporary) {
+ debug("Removing temporary device %s", device->address);
+ adapter_remove_device(connection, adapter, device);
+ }
+ }
+}
+
+int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited)
+{
+ uint32_t dev_class;
+ int err;
+ int num = (limited ? 2 : 1);
+ uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
+ /*
+ * 1: giac
+ * 2: giac + liac
+ */
+ if (hci_write_current_iac_lap(dd, num, lap, 1000) < 0) {
+ err = errno;
+ error("Can't write current IAC LAP: %s(%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ if (limited) {
+ if (cls[1] & 0x20)
+ return 0; /* Already limited */
+
+ dev_class = (cls[2] << 16) | ((cls[1] | 0x20) << 8) | cls[0];
+ } else {
+ if (!(cls[1] & 0x20))
+ return 0; /* Already clear */
+
+ dev_class = (cls[2] << 16) | ((cls[1] & 0xdf) << 8) | cls[0];
+ }
+
+ if (hci_write_class_of_dev(dd, dev_class, 1000) < 0) {
+ err = errno;
+ error("Can't write class of device: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ return 0;
+}
+
+int set_service_classes(int dd, const uint8_t *cls, uint8_t value)
+{
+ uint32_t dev_class;
+ int err;
+
+ if (cls[2] == value)
+ return 0; /* Already set */
+
+ dev_class = (value << 16) | (cls[1] << 8) | cls[0];
+
+ if (hci_write_class_of_dev(dd, dev_class, 1000) < 0) {
+ err = errno;
+ error("Can't write class of device: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ return 0;
+}
+
+gboolean discov_timeout_handler(void *data)
+{
+ struct adapter *adapter = data;
+ struct hci_request rq;
+ int dd;
+ uint8_t scan_enable = adapter->scan_enable;
+ uint8_t status = 0;
+ gboolean retval = TRUE;
+
+ scan_enable &= ~SCAN_INQUIRY;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("HCI device open failed: hci%d", adapter->dev_id);
+ return TRUE;
+ }
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_WRITE_SCAN_ENABLE;
+ rq.cparam = &scan_enable;
+ rq.clen = sizeof(scan_enable);
+ rq.rparam = &status;
+ rq.rlen = sizeof(status);
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, 1000) < 0) {
+ error("Sending write scan enable command to hci%d failed: %s (%d)",
+ adapter->dev_id, strerror(errno), errno);
+ goto failed;
+ }
+ if (status) {
+ error("Setting scan enable failed with status 0x%02x", status);
+ goto failed;
+ }
+
+ set_limited_discoverable(dd, adapter->class, FALSE);
+
+ adapter->timeout_id = 0;
+ retval = FALSE;
+
+failed:
+ if (dd >= 0)
+ hci_close_dev(dd);
+
+ return retval;
+}
+
+/* Section reserved to device HCI callbacks */
+
+void hcid_dbus_setname_complete(bdaddr_t *local)
+{
+ int id, dd = -1;
+ read_local_name_rp rp;
+ struct hci_request rq;
+ const char *pname = (char *) rp.name;
+ char local_addr[18], name[249];
+
+ ba2str(local, local_addr);
+
+ id = hci_devid(local_addr);
+ if (id < 0) {
+ error("No matching device id for %s", local_addr);
+ return;
+ }
+
+ dd = hci_open_dev(id);
+ if (dd < 0) {
+ error("HCI device open failed: hci%d", id);
+ memset(&rp, 0, sizeof(rp));
+ } else {
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_READ_LOCAL_NAME;
+ rq.rparam = &rp;
+ rq.rlen = READ_LOCAL_NAME_RP_SIZE;
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, 1000) < 0) {
+ error("Sending getting name command failed: %s (%d)",
+ strerror(errno), errno);
+ rp.name[0] = '\0';
+ } else if (rp.status) {
+ error("Getting name failed with status 0x%02x",
+ rp.status);
+ rp.name[0] = '\0';
+ }
+ hci_close_dev(dd);
+ }
+
+ strncpy(name, pname, sizeof(name) - 1);
+ name[248] = '\0';
+ pname = name;
+
+ send_adapter_signal(connection, id, "NameChanged",
+ DBUS_TYPE_STRING, &pname, DBUS_TYPE_INVALID);
+}
+
+void hcid_dbus_setscan_enable_complete(bdaddr_t *local)
+{
+ struct adapter *adapter;
+ read_scan_enable_rp rp;
+ struct hci_request rq;
+ int dd = -1;
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("HCI device open failed: hci%d", adapter->dev_id);
+ return;
+ }
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_READ_SCAN_ENABLE;
+ rq.rparam = &rp;
+ rq.rlen = READ_SCAN_ENABLE_RP_SIZE;
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, 1000) < 0) {
+ error("Sending read scan enable command failed: %s (%d)",
+ strerror(errno), errno);
+ goto failed;
+ }
+
+ if (rp.status) {
+ error("Getting scan enable failed with status 0x%02x",
+ rp.status);
+ goto failed;
+ }
+
+ if (adapter->timeout_id) {
+ g_source_remove(adapter->timeout_id);
+ adapter->timeout_id = 0;
+ }
+
+ if (adapter->scan_enable != rp.enable)
+ adapter_mode_changed(adapter, rp.enable);
+
+failed:
+ if (dd >= 0)
+ hci_close_dev(dd);
+}
+
+void hcid_dbus_write_class_complete(bdaddr_t *local)
+{
+ struct adapter *adapter;
+ int dd;
+ uint8_t cls[3];
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return;
+ }
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ error("HCI device open failed: hci%d", adapter->dev_id);
+ return;
+ }
+
+ if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
+ error("Can't read class of device on hci%d: %s (%d)",
+ adapter->dev_id, strerror(errno), errno);
+ hci_close_dev(dd);
+ return;
+ }
+
+ write_local_class(local, cls);
+ set_device_class(adapter->dev_id, cls);
+ memcpy(adapter->class, cls, 3);
+
+ hci_close_dev(dd);
+}
+
+void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local)
+{
+ char addr[18];
+ int dev_id, dd;
+ uint8_t mode;
+
+ ba2str(local, addr);
+
+ dev_id = hci_devid(addr);
+ if (dev_id < 0) {
+ error("No matching device id for %s", addr);
+ return;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ error("HCI device open failed: hci%d", dev_id);
+ return;
+ }
+
+ if (hci_read_simple_pairing_mode(dd, &mode, 1000) < 0) {
+ error("Can't read class of device on hci%d: %s(%d)",
+ dev_id, strerror(errno), errno);
+ hci_close_dev(dd);
+ return;
+ }
+
+ set_simple_pairing_mode(dev_id, mode);
+
+ hci_close_dev(dd);
+}
+
+int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
+ uint8_t *cap, uint8_t *auth)
+{
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ char addr[18];
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ if (get_auth_requirements(local, remote, auth) < 0)
+ return -1;
+
+ ba2str(remote, addr);
+
+ device = adapter_find_device(adapter, addr);
+ if (device && device->agent) {
+ agent = device->agent;
+ *auth = 0x03;
+ } else
+ agent = adapter->agent;
+
+ if (!agent) {
+ if (!(*auth & 0x01)) {
+ /* No input, no output */
+ *cap = 0x03;
+ return 0;
+ }
+ error("No agent available for IO capability");
+ return -1;
+ }
+
+ *cap = agent_get_io_capability(agent);
+
+ return 0;
+}
+
+int hcid_dbus_set_io_cap(bdaddr_t *local, bdaddr_t *remote,
+ uint8_t cap, uint8_t auth)
+{
+ struct adapter *adapter;
+ struct device *device;
+ char addr[18];
+
+ adapter = manager_find_adapter(local);
+ if (!adapter) {
+ error("No matching adapter found");
+ return -1;
+ }
+
+ ba2str(remote, addr);
+
+ device = adapter_get_device(connection, adapter, addr);
+ if (device) {
+ device->cap = cap;
+ device->auth = auth;
+ }
+
+ return 0;
+}
+
+static int inquiry_cancel(int dd, int to)
+{
+ struct hci_request rq;
+ uint8_t status;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_INQUIRY_CANCEL;
+ rq.rparam = &status;
+ rq.rlen = sizeof(status);
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, to) < 0)
+ return -1;
+
+ if (status) {
+ errno = bt_error(status);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int remote_name_cancel(int dd, bdaddr_t *dba, int to)
+{
+ remote_name_req_cancel_cp cp;
+ struct hci_request rq;
+ uint8_t status;
+
+ memset(&rq, 0, sizeof(rq));
+ memset(&cp, 0, sizeof(cp));
+
+ bacpy(&cp.bdaddr, dba);
+
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_REMOTE_NAME_REQ_CANCEL;
+ rq.cparam = &cp;
+ rq.clen = REMOTE_NAME_REQ_CANCEL_CP_SIZE;
+ rq.rparam = &status;
+ rq.rlen = sizeof(status);
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, to) < 0)
+ return -1;
+
+ if (status) {
+ errno = bt_error(status);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cancel_discovery(struct adapter *adapter)
+{
+ struct remote_dev_info *dev, match;
+ GSList *l;
+ int dd, err = 0;
+
+ if (!adapter->discov_active)
+ goto cleanup;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ err = -ENODEV;
+ goto cleanup;
+ }
+
+ /*
+ * If there is a pending read remote name request means
+ * that the inquiry complete event was already received
+ */
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, BDADDR_ANY);
+ match.name_status = NAME_REQUESTED;
+
+ l = g_slist_find_custom(adapter->found_devices, &match,
+ (GCompareFunc) found_device_cmp);
+ if (l) {
+ dev = l->data;
+ if (remote_name_cancel(dd, &dev->bdaddr, 1000) < 0) {
+ error("Read remote name cancel failed: %s, (%d)",
+ strerror(errno), errno);
+ err = -errno;
+ }
+ } else {
+ if (inquiry_cancel(dd, 1000) < 0) {
+ error("Inquiry cancel failed:%s (%d)",
+ strerror(errno), errno);
+ err = -errno;
+ }
+ }
+
+ hci_close_dev(dd);
+
+cleanup:
+ /*
+ * Reset discov_requestor and discover_state in the remote name
+ * request event handler or in the inquiry complete handler.
+ */
+ g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+
+ /* Disable name resolution for non D-Bus clients */
+ if (!adapter->pdiscov_requestor)
+ adapter->discov_type &= ~RESOLVE_NAME;
+
+ return err;
+}
+
+static int periodic_inquiry_exit(int dd, int to)
+{
+ struct hci_request rq;
+ uint8_t status;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_EXIT_PERIODIC_INQUIRY;
+ rq.rparam = &status;
+ rq.rlen = sizeof(status);
+ rq.event = EVT_CMD_COMPLETE;
+
+ if (hci_send_req(dd, &rq, to) < 0)
+ return -1;
+
+ if (status) {
+ errno = status;
+ return -1;
+ }
+
+ return 0;
+}
+
+int cancel_periodic_discovery(struct adapter *adapter)
+{
+ struct remote_dev_info *dev, match;
+ GSList *l;
+ int dd, err = 0;
+
+ if (!adapter->pdiscov_active)
+ goto cleanup;
+
+ dd = hci_open_dev(adapter->dev_id);
+ if (dd < 0) {
+ err = -ENODEV;
+ goto cleanup;
+ }
+ /* find the pending remote name request */
+ memset(&match, 0, sizeof(struct remote_dev_info));
+ bacpy(&match.bdaddr, BDADDR_ANY);
+ match.name_status = NAME_REQUESTED;
+
+ l = g_slist_find_custom(adapter->found_devices, &match,
+ (GCompareFunc) found_device_cmp);
+ if (l) {
+ dev = l->data;
+ if (remote_name_cancel(dd, &dev->bdaddr, 1000) < 0) {
+ error("Read remote name cancel failed: %s, (%d)",
+ strerror(errno), errno);
+ err = -errno;
+ }
+ }
+
+ /* ovewrite err if necessary: stop periodic inquiry has higher
+ * priority */
+ if (periodic_inquiry_exit(dd, 1000) < 0) {
+ error("Periodic Inquiry exit failed:%s (%d)",
+ strerror(errno), errno);
+ err = -errno;
+ }
+
+ hci_close_dev(dd);
+
+cleanup:
+ /*
+ * Reset pdiscov_requestor and pdiscov_active is done when the
+ * cmd complete event for exit periodic inquiry mode cmd arrives.
+ */
+ g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
+ g_slist_free(adapter->found_devices);
+ adapter->found_devices = NULL;
+
+ return err;
+}
+
+/* Most of the functions in this module require easy access to a connection so
+ * we keep it global here and provide these access functions the other (few)
+ * modules that require access to it */
+
+void set_dbus_connection(DBusConnection *conn)
+{
+ connection = conn;
+}
+
+DBusConnection *get_dbus_connection(void)
+{
+ return connection;
+}
diff --git a/utils/hcid/dbus-hci.h b/utils/hcid/dbus-hci.h
new file mode 100644
index 00000000..cb618816
--- /dev/null
+++ b/utils/hcid/dbus-hci.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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 hcid_dbus_set_experimental();
+int hcid_dbus_use_experimental();
+int hcid_dbus_register_device(uint16_t id);
+int hcid_dbus_unregister_device(uint16_t id);
+int hcid_dbus_start_device(uint16_t id);
+int hcid_dbus_stop_device(uint16_t id);
+int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci);
+
+void hcid_dbus_inquiry_start(bdaddr_t *local);
+void hcid_dbus_inquiry_complete(bdaddr_t *local);
+void hcid_dbus_periodic_inquiry_start(bdaddr_t *local, uint8_t status);
+void hcid_dbus_periodic_inquiry_exit(bdaddr_t *local, uint8_t status);
+void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, int8_t rssi, uint8_t *data);
+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);
+void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, uint8_t reason);
+void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
+void hcid_dbus_setname_complete(bdaddr_t *local);
+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);
+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,
+ uint8_t cap, uint8_t auth);
+int hcid_dbus_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
+int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba);
+int hcid_dbus_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
+
+int unregister_adapter_path(const char *path);
+
+DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status);
+
+int get_default_dev_id(void);
+
+int cancel_discovery(struct adapter *adapter);
+int cancel_periodic_discovery(struct adapter *adapter);
+
+int active_conn_find_by_bdaddr(const void *data, const void *user_data);
+void bonding_request_free(struct bonding_request_info *dev);
+int found_device_cmp(const struct remote_dev_info *d1,
+ const struct remote_dev_info *d2);
+int found_device_add(GSList **list, bdaddr_t *bdaddr, int8_t rssi,
+ name_status_t name_status);
+int found_device_req_name(struct adapter *dbus_data);
+
+int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited);
+int set_service_classes(int dd, const uint8_t *cls, uint8_t value);
+
+int discov_timeout_handler(void *data);
+
+void set_dbus_connection(DBusConnection *conn);
+
+DBusConnection *get_dbus_connection(void);
+struct adapter *adapter_find(const bdaddr_t *sba);
diff --git a/utils/hcid/dbus-sdp.c b/utils/hcid/dbus-sdp.c
new file mode 100644
index 00000000..02f9e31c
--- /dev/null
+++ b/utils/hcid/dbus-sdp.c
@@ -0,0 +1,1125 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <netinet/in.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "textfile.h"
+#include "adapter.h"
+#include "dbus-hci.h"
+#include "dbus-common.h"
+#include "dbus-error.h"
+#include "error.h"
+#include "dbus-sdp.h"
+#include "sdp-xml.h"
+#include "glib-helper.h"
+
+#define SESSION_TIMEOUT 2000
+#define DEFAULT_XML_BUF_SIZE 1024
+
+struct transaction_context {
+ char *src;
+ char *dst;
+ DBusConnection *conn;
+ DBusMessage *rq;
+ sdp_session_t *session;
+ GIOChannel *io;
+ guint io_id;
+ uuid_t uuid;
+ GSList *identifiers;
+};
+
+typedef int connect_cb_t(struct transaction_context *t);
+
+struct pending_connect {
+ DBusConnection *conn;
+ DBusMessage *rq;
+ char *src;
+ char *dst;
+ sdp_session_t *session;
+ connect_cb_t *conn_cb;
+};
+
+struct cached_session {
+ sdp_session_t *session;
+ guint timeout_id;
+ guint io_id;
+};
+
+static GSList *cached_sessions = NULL;
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+}
+
+static inline DBusMessage *in_progress(DBusMessage *msg, const char *str)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", str);
+}
+
+static inline DBusMessage *adapter_not_ready(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady",
+ "Adapter is not ready");
+}
+
+static inline DBusMessage *failed_strerror(DBusMessage *msg, int err)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ strerror(err));
+}
+
+static gboolean session_timeout(gpointer user_data)
+{
+ struct cached_session *s = user_data;
+
+ debug("sdp session timed out. closing");
+
+ cached_sessions = g_slist_remove(cached_sessions, s);
+
+ g_source_remove(s->io_id);
+ sdp_close(s->session);
+ g_free(s);
+
+ return FALSE;
+}
+
+gboolean idle_callback(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+ struct cached_session *s = user_data;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_ERR | G_IO_HUP))
+ debug("idle_callback: session got disconnected");
+
+ if (cond & G_IO_IN)
+ debug("got unexpected input on idle SDP socket");
+
+ cached_sessions = g_slist_remove(cached_sessions, s);
+
+ g_source_remove(s->timeout_id);
+ sdp_close(s->session);
+ g_free(s);
+
+ return FALSE;
+}
+
+static void cache_sdp_session(sdp_session_t *sess, GIOChannel *io)
+{
+ struct cached_session *s;
+
+ s = g_new0(struct cached_session, 1);
+
+ s->session = sess;
+ s->timeout_id = g_timeout_add(SESSION_TIMEOUT, session_timeout, s);
+ s->io_id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ idle_callback, s);
+
+ cached_sessions = g_slist_append(cached_sessions, s);
+
+ debug("sdp session added to cache");
+}
+
+static int get_bdaddrs(int sock, bdaddr_t *sba, bdaddr_t *dba)
+{
+ struct sockaddr_l2 a;
+ socklen_t len;
+
+ len = sizeof(a);
+ if (getsockname(sock, (struct sockaddr *) &a, &len) < 0) {
+ error("getsockname: %s (%d)", strerror(errno), errno);
+ return -1;
+ }
+
+ bacpy(sba, &a.l2_bdaddr);
+
+ len = sizeof(a);
+ if (getpeername(sock, (struct sockaddr *) &a, &len) < 0) {
+ error("getpeername: %s (%d)", strerror(errno), errno);
+ return -1;
+ }
+
+ bacpy(dba, &a.l2_bdaddr);
+
+ return 0;
+}
+
+static struct cached_session *get_cached_session(bdaddr_t *src, bdaddr_t *dst)
+{
+ GSList *l;
+
+ for (l = cached_sessions; l != NULL; l = l->next) {
+ struct cached_session *s = l->data;
+ int sock = sdp_get_socket(s->session);
+ bdaddr_t sba, dba;
+
+ if (get_bdaddrs(sock, &sba, &dba) < 0)
+ continue;
+
+ if (bacmp(&sba, src) || bacmp(&dba, dst))
+ continue;
+
+ debug("found matching session, removing from list");
+
+ cached_sessions = g_slist_remove(cached_sessions, s);
+
+ return s;
+ }
+
+ return NULL;
+}
+
+static sdp_session_t *get_sdp_session(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct cached_session *s;
+ sdp_session_t *session;
+
+ s = get_cached_session(src, dst);
+ if (!s) {
+ debug("no matching session found. creating a new one");
+ return sdp_connect(src, dst, SDP_NON_BLOCKING);
+ }
+
+ session = s->session;
+
+ g_source_remove(s->timeout_id);
+ g_source_remove(s->io_id);
+ g_free(s);
+
+ return session;
+}
+
+void append_and_grow_string(void *data, const char *str)
+{
+ sdp_buf_t *buff = data;
+ int len;
+
+ len = strlen(str);
+
+ if (!buff->data) {
+ buff->data = malloc(DEFAULT_XML_BUF_SIZE);
+ if (!buff->data)
+ return;
+ buff->buf_size = DEFAULT_XML_BUF_SIZE;
+ }
+
+ /* Grow string */
+ while (buff->buf_size < (buff->data_size + len + 1)) {
+ void *tmp;
+ uint32_t new_size;
+
+ /* Grow buffer by a factor of 2 */
+ new_size = (buff->buf_size << 1);
+
+ tmp = realloc(buff->data, new_size);
+ if (!tmp)
+ return;
+
+ buff->data = tmp;
+ buff->buf_size = new_size;
+ }
+
+ /* Include the NULL character */
+ memcpy(buff->data + buff->data_size, str, len + 1);
+ buff->data_size += len;
+}
+
+/* list of remote and local service records */
+static GSList *pending_connects = NULL;
+
+static struct pending_connect *pending_connect_new(DBusConnection *conn,
+ DBusMessage *msg, const char *src,
+ const char *dst, connect_cb_t *cb)
+{
+ struct pending_connect *c;
+
+ if (!dst)
+ return NULL;
+
+ c = g_new0(struct pending_connect, 1);
+ c->src = g_strdup(src);
+ c->dst = g_strdup(dst);
+ c->conn = dbus_connection_ref(conn);
+ c->rq = dbus_message_ref(msg);
+ c->conn_cb = cb;
+
+ return c;
+}
+
+static void pending_connect_free(struct pending_connect *c)
+{
+ if (!c)
+ return;
+
+ g_free(c->src);
+ g_free(c->dst);
+
+ if (c->rq)
+ dbus_message_unref(c->rq);
+
+ if (c->conn)
+ dbus_connection_unref(c->conn);
+
+ g_free(c);
+}
+
+static struct pending_connect *find_pending_connect(const char *dst)
+{
+ GSList *l;
+
+ for (l = pending_connects; l != NULL; l = l->next) {
+ struct pending_connect *pending = l->data;
+ if (!strcmp(dst, pending->dst))
+ return pending;
+ }
+
+ return NULL;
+}
+
+static int sdp_store_record(const char *src, const char *dst, uint32_t handle, uint8_t *buf, size_t size)
+{
+ char filename[PATH_MAX + 1], key[28], *value;
+ int i, err;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ snprintf(key, sizeof(key), "%17s#%08X", dst, handle);
+
+ value = g_malloc0(size * 2 + 1);
+
+ for (i = 0; i < size; i++)
+ sprintf(value + (i * 2), "%02X", buf[i]);
+
+ err = textfile_put(filename, key, value);
+
+ g_free(value);
+
+ return err;
+}
+
+static void transaction_context_free(void *udata, gboolean cache)
+{
+ struct transaction_context *ctxt = udata;
+
+ if (!ctxt)
+ return;
+
+ g_free(ctxt->src);
+ g_free(ctxt->dst);
+
+ if (ctxt->conn)
+ dbus_connection_unref(ctxt->conn);
+
+ if (ctxt->rq)
+ dbus_message_unref(ctxt->rq);
+
+ if (ctxt->session && !ctxt->io)
+ sdp_close(ctxt->session);
+
+ if (ctxt->session && ctxt->io) {
+ g_source_remove(ctxt->io_id);
+
+ if (cache)
+ cache_sdp_session(ctxt->session, ctxt->io);
+ else
+ sdp_close(ctxt->session);
+
+ g_io_channel_unref(ctxt->io);
+ }
+
+ if (ctxt->identifiers) {
+ g_slist_foreach(ctxt->identifiers, (GFunc) g_free, NULL);
+ g_slist_free(ctxt->identifiers);
+ }
+
+ g_free(ctxt);
+}
+
+static gboolean search_process_cb(GIOChannel *chan,
+ GIOCondition cond, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ int err = 0;
+
+ if (cond & G_IO_NVAL) {
+ g_io_channel_unref(chan);
+ return FALSE;
+ }
+
+ if (cond & (G_IO_ERR | G_IO_HUP)) {
+ err = EIO;
+ goto failed;
+ }
+
+ if (sdp_process(ctxt->session) < 0)
+ goto failed;
+
+ return TRUE;
+
+failed:
+ if (err) {
+ error_failed_errno(ctxt->conn, ctxt->rq, err);
+ transaction_context_free(ctxt, FALSE);
+ }
+
+ return TRUE;
+}
+
+static void remote_svc_rec_completed_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ sdp_record_t *rec;
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ int scanned;
+
+ if (!ctxt)
+ return;
+
+ if (err == 0xffff) {
+ /* Check for protocol error or I/O error */
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ error_failed_errno(ctxt->conn, ctxt->rq, EINVAL);
+ goto failed;
+ }
+
+ error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+ error_failed_errno(ctxt->conn, ctxt->rq, sdp_err);
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP) {
+ error_sdp_failed(ctxt->conn, ctxt->rq, err);
+ goto failed;
+ }
+
+ /* check response PDU ID */
+ if (type != SDP_SVC_ATTR_RSP) {
+ error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+ error_failed_errno(ctxt->conn, ctxt->rq, EPROTO);
+ goto failed;
+ }
+
+ reply = dbus_message_new_method_return(ctxt->rq);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &array_iter);
+
+ rec = sdp_extract_pdu_safe(rsp, size, &scanned);
+ if (rec == NULL || size != scanned) {
+ error("Invalid service record!");
+ goto done;
+ }
+
+ sdp_store_record(ctxt->src, ctxt->dst, rec->handle, rsp, size);
+
+ sdp_record_free(rec);
+
+ dbus_message_iter_append_fixed_array(&array_iter,
+ DBUS_TYPE_BYTE, &rsp, size);
+
+done:
+ dbus_message_iter_close_container(&iter, &array_iter);
+ dbus_connection_send(ctxt->conn, reply, NULL);
+ dbus_message_unref(reply);
+
+failed:
+ transaction_context_free(ctxt, TRUE);
+}
+
+static void remote_svc_rec_completed_xml_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size,
+ void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ sdp_record_t *rec;
+ DBusMessage *reply;
+ int scanned;
+ sdp_buf_t result;
+
+ if (!ctxt)
+ return;
+
+ if (err == 0xffff) {
+ /* Check for protocol error or I/O error */
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ error_failed_errno(ctxt->conn, ctxt->rq, EINVAL);
+ goto failed;
+ }
+
+ error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+ error_failed_errno(ctxt->conn, ctxt->rq, sdp_err);
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP) {
+ error_sdp_failed(ctxt->conn, ctxt->rq, err);
+ goto failed;
+ }
+
+ /* check response PDU ID */
+ if (type != SDP_SVC_ATTR_RSP) {
+ error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+ error_failed_errno(ctxt->conn, ctxt->rq, EPROTO);
+ goto failed;
+ }
+
+ reply = dbus_message_new_method_return(ctxt->rq);
+
+ rec = sdp_extract_pdu_safe(rsp, size, &scanned);
+ if (rec == NULL || size != scanned) {
+ error("Invalid service record!");
+ goto done;
+ }
+
+ sdp_store_record(ctxt->src, ctxt->dst, rec->handle, rsp, size);
+
+ memset(&result, 0, sizeof(sdp_buf_t));
+
+ convert_sdp_record_to_xml(rec, &result, append_and_grow_string);
+
+ sdp_record_free(rec);
+
+ if (result.data) {
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &result.data,
+ DBUS_TYPE_INVALID);
+
+ free(result.data);
+ }
+done:
+ dbus_connection_send(ctxt->conn, reply, NULL);
+ dbus_message_unref(reply);
+
+failed:
+ transaction_context_free(ctxt, TRUE);
+}
+
+static void remote_svc_handles_completed_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ uint8_t *pdata;
+ int csrc, tsrc;
+
+ if (!ctxt)
+ return;
+
+ if (err == 0xffff) {
+ /* Check for protocol error or I/O error */
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ error_failed_errno(ctxt->conn, ctxt->rq, EINVAL);
+ goto failed;
+ }
+
+ error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+ error_failed_errno(ctxt->conn, ctxt->rq, sdp_err);
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP) {
+ error_sdp_failed(ctxt->conn, ctxt->rq, err);
+ goto failed;
+ }
+
+ /* check response PDU ID */
+ if (type != SDP_SVC_SEARCH_RSP) {
+ error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+ error_failed_errno(ctxt->conn, ctxt->rq, EPROTO);
+ goto failed;
+ }
+
+ reply = dbus_message_new_method_return(ctxt->rq);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_UINT32_AS_STRING, &array_iter);
+
+ pdata = rsp;
+
+ tsrc = ntohs(bt_get_unaligned((uint16_t *) pdata));
+ if (tsrc <= 0)
+ goto done;
+
+ pdata += sizeof(uint16_t);
+
+ csrc = ntohs(bt_get_unaligned((uint16_t *) pdata));
+ if (csrc <= 0)
+ goto done;
+
+ pdata += sizeof(uint16_t);
+
+ do {
+ uint32_t handle = ntohl(bt_get_unaligned((uint32_t*)pdata));
+ pdata += sizeof(uint32_t);
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_UINT32, &handle);
+ } while (--tsrc);
+
+
+done:
+ dbus_message_iter_close_container(&iter, &array_iter);
+ dbus_connection_send(ctxt->conn, reply, NULL);
+ dbus_message_unref(reply);
+
+failed:
+ transaction_context_free(ctxt, TRUE);
+}
+
+static const char *extract_service_class(sdp_data_t *d)
+{
+ sdp_data_t *seq;
+ uuid_t *uuid;
+ static char uuid_str[37];
+
+ /* Expected sequence of UUID16 */
+ if (d->attrId != SDP_ATTR_SVCLASS_ID_LIST)
+ return NULL;
+
+ if (d->dtd != SDP_SEQ8 && d->dtd != SDP_SEQ16 && d->dtd != SDP_SEQ32)
+ return NULL;
+
+ if (!d->val.dataseq)
+ return NULL;
+
+ seq = d->val.dataseq;
+ if (!SDP_IS_UUID(seq->dtd))
+ return NULL;
+
+ uuid = &seq->val.uuid;
+ if (uuid->type != SDP_UUID16)
+ return NULL;
+
+ sprintf(uuid_str, "0000%04x-0000-1000-8000-00805f9b34fb",
+ uuid->value.uuid16);
+
+ return uuid_str;
+}
+
+static int service_search_attr(struct transaction_context *ctxt, uint16_t uuid)
+{
+ sdp_list_t *attrids, *search;
+ uint32_t range = 0x0000ffff;
+ int ret = 0;
+
+ sdp_uuid16_create(&ctxt->uuid, uuid);
+
+ search = sdp_list_append(0, &ctxt->uuid);
+ attrids = sdp_list_append(NULL, &range);
+
+ /*
+ * Create/send the search request and set the
+ * callback to indicate the request completion
+ */
+ if (sdp_service_search_attr_async(ctxt->session, search,
+ SDP_ATTR_REQ_RANGE, attrids) < 0)
+ ret = -sdp_get_error(ctxt->session);
+
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrids, NULL);
+
+ return ret;
+}
+
+static void remote_svc_identifiers_completed_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ const char *puuid;
+ const char *devid_uuid = "00001200-0000-1000-8000-00805f9b34fb";
+ char **identifiers;
+ DBusMessage *reply;
+ GSList *l = NULL;
+ int scanned, extracted = 0, len = 0, recsize = 0, bytesleft = size;
+ uint8_t dtd = 0;
+
+ if (!ctxt)
+ return;
+
+ if (err == 0xffff) {
+ /* Check for protocol error or I/O error */
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ error_failed_errno(ctxt->conn, ctxt->rq, EINVAL);
+ goto failed;
+ }
+
+ error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+ error_failed_errno(ctxt->conn, ctxt->rq, sdp_err);
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP) {
+ error_sdp_failed(ctxt->conn, ctxt->rq, err);
+ goto failed;
+ }
+
+ /* Check response PDU ID */
+ if (type != SDP_SVC_SEARCH_ATTR_RSP) {
+ error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+ error_failed_errno(ctxt->conn, ctxt->rq, EPROTO);
+ goto failed;
+ }
+
+ scanned = sdp_extract_seqtype_safe(rsp, bytesleft, &dtd, &len);
+ rsp += scanned;
+ bytesleft -= scanned;
+ for (; extracted < len; rsp += recsize, extracted += recsize, bytesleft -= recsize) {
+ sdp_record_t *rec;
+ sdp_data_t *d;
+
+ recsize = 0;
+ rec = sdp_extract_pdu_safe(rsp, bytesleft, &recsize);
+ if (!rec)
+ break;
+
+ sdp_store_record(ctxt->src, ctxt->dst, rec->handle, rsp, recsize);
+
+ d = sdp_data_get(rec, SDP_ATTR_SVCLASS_ID_LIST);
+ if (!d) {
+ sdp_record_free(rec);
+ continue;
+ }
+
+ puuid = extract_service_class(d);
+ sdp_record_free(rec);
+ if (!puuid)
+ continue;
+
+ /* Ignore repeated identifiers */
+ l = g_slist_find_custom(ctxt->identifiers,
+ puuid, (GCompareFunc) strcmp);
+ if (l)
+ continue;
+
+ ctxt->identifiers = g_slist_append(ctxt->identifiers,
+ g_strdup(puuid));
+ }
+
+ /* If public browse response is empty: search for L2CAP */
+ if (!ctxt->identifiers && ctxt->uuid.value.uuid16 == PUBLIC_BROWSE_GROUP)
+ if (service_search_attr(ctxt, L2CAP_UUID) == 0)
+ return; /* Wait the response */
+
+ /* Request DeviceID if it was not returned previously */
+ l = g_slist_find_custom(ctxt->identifiers,
+ devid_uuid, (GCompareFunc) strcmp);
+ if (!l && ctxt->uuid.value.uuid16 != PNP_INFO_SVCLASS_ID)
+ if (service_search_attr(ctxt, PNP_INFO_SVCLASS_ID) == 0)
+ return; /* Wait the response */
+
+ reply = dbus_message_new_method_return(ctxt->rq);
+
+ identifiers = g_new(char *, g_slist_length(ctxt->identifiers));
+
+ for (l = ctxt->identifiers, len = 0; l; l = l->next, len++)
+ identifiers[len] = l->data;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &identifiers, len,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(ctxt->conn, reply, NULL);
+ dbus_message_unref(reply);
+
+ if (len)
+ g_dbus_emit_signal(ctxt->conn,
+ dbus_message_get_path(ctxt->rq),
+ ADAPTER_INTERFACE,
+ "RemoteIdentifiersUpdated",
+ DBUS_TYPE_STRING, &ctxt->dst,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &identifiers, len,
+ DBUS_TYPE_INVALID);
+
+ if (identifiers)
+ g_free(identifiers);
+
+failed:
+ transaction_context_free(ctxt, TRUE);
+}
+
+static gboolean sdp_client_connect_cb(GIOChannel *chan,
+ GIOCondition cond, void *udata)
+{
+ struct pending_connect *c = udata;
+ struct transaction_context *ctxt = NULL;
+ int sdp_err, err = 0, sk;
+ socklen_t len;
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ len = sizeof(err);
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
+ error("getsockopt(): %s (%d)", strerror(errno), errno);
+ err = errno;
+ goto failed;
+ }
+ if (err != 0) {
+ error("connect(): %s (%d)", strerror(err), err);
+ goto failed;
+ }
+
+ ctxt = g_new0(struct transaction_context, 1);
+ ctxt->src = g_strdup(c->src);
+ ctxt->dst = g_strdup(c->dst);
+ ctxt->conn = dbus_connection_ref(c->conn);
+ ctxt->rq = dbus_message_ref(c->rq);
+ ctxt->session = c->session;
+
+ /* set the complete transaction callback and send the search request */
+ sdp_err = c->conn_cb(ctxt);
+ if (sdp_err < 0) {
+ err = -sdp_err;
+ error("search failed: %s (%d)", strerror(err), err);
+ goto failed;
+ }
+
+ /* set the callback responsible for update the transaction data */
+ ctxt->io_id = g_io_add_watch(chan,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ search_process_cb, ctxt);
+ ctxt->io = g_io_channel_ref(chan);
+
+ goto done;
+
+failed:
+ error_connection_attempt_failed(c->conn, c->rq, err);
+
+ if (ctxt)
+ transaction_context_free(ctxt, FALSE);
+ else
+ sdp_close(c->session);
+
+done:
+ pending_connects = g_slist_remove(pending_connects, c);
+ pending_connect_free(c);
+
+ return FALSE;
+}
+
+static struct pending_connect *connect_request(DBusConnection *conn,
+ DBusMessage *msg,
+ const char *src,
+ const char *dst,
+ connect_cb_t *cb, int *err)
+{
+ struct pending_connect *c;
+ bdaddr_t srcba, dstba;
+ GIOChannel *chan;
+
+ c = pending_connect_new(conn, msg, src, dst, cb);
+ if (!c) {
+ if (err)
+ *err = ENOMEM;
+ return NULL;
+ }
+
+ str2ba(src, &srcba);
+ str2ba(dst, &dstba);
+ c->session = get_sdp_session(&srcba, &dstba);
+ if (!c->session) {
+ if (err)
+ *err = errno;
+ error("sdp_connect() failed: %s (%d)", strerror(errno), errno);
+ pending_connect_free(c);
+ return NULL;
+ }
+
+ chan = g_io_channel_unix_new(sdp_get_socket(c->session));
+ g_io_add_watch(chan, G_IO_OUT, sdp_client_connect_cb, c);
+ g_io_channel_unref(chan);
+ pending_connects = g_slist_append(pending_connects, c);
+
+ return c;
+}
+
+static int remote_svc_rec_conn_cb(struct transaction_context *ctxt)
+{
+ sdp_list_t *attrids;
+ uint32_t range = 0x0000ffff;
+ const char *dst;
+ uint32_t handle;
+
+ if (sdp_set_notify(ctxt->session, remote_svc_rec_completed_cb, ctxt) < 0)
+ return -EINVAL;
+
+ dbus_message_get_args(ctxt->rq, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+
+ attrids = sdp_list_append(NULL, &range);
+ /*
+ * Create/send the search request and set the
+ * callback to indicate the request completion
+ */
+ if (sdp_service_attr_async(ctxt->session, handle,
+ SDP_ATTR_REQ_RANGE, attrids) < 0) {
+ sdp_list_free(attrids, NULL);
+ return -sdp_get_error(ctxt->session);
+ }
+
+ sdp_list_free(attrids, NULL);
+
+ return 0;
+}
+
+static int remote_svc_rec_conn_xml_cb(struct transaction_context *ctxt)
+{
+ sdp_list_t *attrids;
+ uint32_t range = 0x0000ffff;
+ const char *dst;
+ uint32_t handle;
+
+ if (sdp_set_notify(ctxt->session, remote_svc_rec_completed_xml_cb, ctxt) < 0)
+ return -EINVAL;
+
+ dbus_message_get_args(ctxt->rq, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+
+ attrids = sdp_list_append(NULL, &range);
+ /*
+ * Create/send the search request and set the
+ * callback to indicate the request completion
+ */
+ if (sdp_service_attr_async(ctxt->session, handle,
+ SDP_ATTR_REQ_RANGE, attrids) < 0) {
+ sdp_list_free(attrids, NULL);
+ return -sdp_get_error(ctxt->session);
+ }
+
+ sdp_list_free(attrids, NULL);
+
+ return 0;
+}
+
+DBusMessage *get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg,
+ void *data, sdp_format_t format)
+{
+ struct adapter *adapter = data;
+ const char *dst;
+ uint32_t handle;
+ int err;
+ connect_cb_t *cb;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (find_pending_connect(dst))
+ return in_progress(msg, "Service search in progress");
+
+ cb = remote_svc_rec_conn_cb;
+ if (format == SDP_FORMAT_XML)
+ cb = remote_svc_rec_conn_xml_cb;
+
+ if (!connect_request(conn, msg, adapter->address,
+ dst, cb, &err)) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ return failed_strerror(msg, err);
+ }
+
+ return NULL;
+}
+
+static int remote_svc_handles_conn_cb(struct transaction_context *ctxt)
+{
+ sdp_list_t *search = NULL;
+ const char *dst, *svc;
+
+ if (sdp_set_notify(ctxt->session, remote_svc_handles_completed_cb, ctxt) < 0)
+ return -EINVAL;
+
+ dbus_message_get_args(ctxt->rq, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_STRING, &svc,
+ DBUS_TYPE_INVALID);
+
+ if (strlen(svc) > 0)
+ bt_string2uuid(&ctxt->uuid, svc);
+ else
+ sdp_uuid16_create(&ctxt->uuid, PUBLIC_BROWSE_GROUP);
+
+ search = sdp_list_append(0, &ctxt->uuid);
+
+ /* Create/send the search request and set the callback to indicate the request completion */
+ if (sdp_service_search_async(ctxt->session, search, 64) < 0) {
+ error("send request failed: %s (%d)", strerror(errno), errno);
+ sdp_list_free(search, NULL);
+ return -sdp_get_error(ctxt->session);
+ }
+
+ sdp_list_free(search, NULL);
+
+ return 0;
+}
+
+static int remote_svc_identifiers_conn_cb(struct transaction_context *ctxt)
+{
+ if (sdp_set_notify(ctxt->session,
+ remote_svc_identifiers_completed_cb, ctxt) < 0)
+ return -EINVAL;
+
+ return service_search_attr(ctxt, PUBLIC_BROWSE_GROUP);
+}
+
+DBusMessage *get_remote_svc_handles(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *dst, *svc;
+ int err;
+ uuid_t uuid;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_STRING, &svc,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (strlen(svc) > 0) {
+ /* Check if it is a service name string */
+ if (bt_string2uuid(&uuid, svc) < 0) {
+ error("Invalid service class name");
+ return invalid_args(msg);
+ }
+ }
+
+ if (find_pending_connect(dst))
+ return in_progress(msg, "Service search in progress");
+
+ if (!connect_request(conn, msg, adapter->address,
+ dst, remote_svc_handles_conn_cb, &err)) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ return failed_strerror(msg, err);
+ }
+
+ return NULL;
+}
+
+DBusMessage *get_remote_svc_identifiers(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *dst;
+ int err;
+
+ if (!adapter->up)
+ return adapter_not_ready(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (find_pending_connect(dst))
+ return in_progress(msg, "Service search in progress");
+
+ if (!connect_request(conn, msg, adapter->address,
+ dst, remote_svc_identifiers_conn_cb, &err)) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ return failed_strerror(msg, err);
+ }
+
+ return NULL;
+}
+
+DBusMessage *finish_remote_svc_transact(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct cached_session *s;
+ const char *address;
+ struct adapter *adapter = data;
+ bdaddr_t sba, dba;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ str2ba(adapter->address, &sba);
+ str2ba(address, &dba);
+
+ while ((s = get_cached_session(&sba, &dba))) {
+ sdp_close(s->session);
+ g_source_remove(s->timeout_id);
+ g_source_remove(s->io_id);
+ g_free(s);
+ }
+
+ return dbus_message_new_method_return(msg);
+}
diff --git a/utils/hcid/dbus-sdp.h b/utils/hcid/dbus-sdp.h
new file mode 100644
index 00000000..06484bbc
--- /dev/null
+++ b/utils/hcid/dbus-sdp.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+typedef enum {
+ SDP_FORMAT_XML,
+ SDP_FORMAT_BINARY
+} sdp_format_t;
+
+DBusMessage *get_remote_svc_handles(DBusConnection *conn,
+ DBusMessage *msg, void *data);
+
+DBusMessage *get_remote_svc_identifiers(DBusConnection *conn,
+ DBusMessage *msg, void *data);
+
+DBusMessage *get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg,
+ void *data, sdp_format_t format);
+
+DBusMessage *finish_remote_svc_transact(DBusConnection *conn,
+ DBusMessage *msg, void *data);
+
+void append_and_grow_string(void *data, const char *str);
diff --git a/utils/hcid/dbus-security.c b/utils/hcid/dbus-security.c
new file mode 100644
index 00000000..19ba6266
--- /dev/null
+++ b/utils/hcid/dbus-security.c
@@ -0,0 +1,1112 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "adapter.h"
+#include "manager.h"
+#include "hcid.h"
+#include "dbus-common.h"
+#include "dbus-service.h"
+#include "error.h"
+#include "dbus-security.h"
+#include "dbus-hci.h"
+
+#define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */
+#define AGENT_TIMEOUT (10 * 60 * 1000) /* 10 minutes */
+
+struct passkey_agent {
+ struct adapter *adapter;
+ DBusConnection *conn;
+ char *addr;
+ char *name;
+ char *path;
+ GSList *pending_requests;
+ int exited;
+ guint timeout;
+ guint listener_id;
+};
+
+struct pending_agent_request {
+ struct passkey_agent *agent;
+ int dev;
+ bdaddr_t sba;
+ bdaddr_t bda;
+ char *path;
+ DBusPendingCall *call;
+ int old_if;
+ char *pin;
+};
+
+struct authorization_agent {
+ DBusConnection *conn;
+ char *name;
+ char *path;
+ GSList *pending_requests;
+ guint listener_id;
+};
+
+struct auth_agent_req {
+ struct authorization_agent *agent;
+ char *adapter_path;
+ char *address;
+ char *service_path;
+ char *uuid;
+ service_auth_cb cb;
+ void *user_data;
+ DBusPendingCall *call;
+};
+
+static struct passkey_agent *default_agent = NULL;
+static struct authorization_agent *default_auth_agent = NULL;
+
+static void release_agent(struct passkey_agent *agent);
+static void send_cancel_request(struct pending_agent_request *req);
+
+static void passkey_agent_free(struct passkey_agent *agent)
+{
+ GSList *l;
+
+ if (!agent)
+ return;
+
+ for (l = agent->pending_requests; l != NULL; l = l->next) {
+ struct pending_agent_request *req = l->data;
+ struct adapter *adapter = manager_find_adapter(&req->sba);
+
+ hci_send_cmd(req->dev, OGF_LINK_CTL,
+ OCF_PIN_CODE_NEG_REPLY, 6, &req->bda);
+
+ if (adapter)
+ adapter_auth_request_replied(adapter, &req->bda);
+
+ send_cancel_request(req);
+ }
+
+ if (agent->timeout)
+ g_source_remove(agent->timeout);
+
+ if (!agent->exited)
+ release_agent(agent);
+
+ g_free(agent->name);
+ g_free(agent->path);
+ g_free(agent->addr);
+
+ if (agent->conn)
+ dbus_connection_unref(agent->conn);
+
+ g_slist_free(agent->pending_requests);
+
+ g_free(agent);
+}
+
+static void agent_exited(void *user_data)
+{
+ struct passkey_agent *agent = user_data;
+ struct adapter *adapter = agent->adapter;
+
+ debug("Passkey agent exited without calling Unregister");
+
+ agent->exited = 1;
+
+ adapter->passkey_agents = g_slist_remove(adapter->passkey_agents, agent);
+ passkey_agent_free(agent);
+}
+
+static gboolean agent_timeout(struct passkey_agent *agent)
+{
+ struct adapter *adapter = agent->adapter;
+
+ debug("Passkey Agent at %s, %s timed out", agent->name, agent->path);
+
+ if (adapter)
+ adapter->passkey_agents = g_slist_remove(adapter->passkey_agents, agent);
+
+ agent->timeout = 0;
+
+ passkey_agent_free(agent);
+
+ return FALSE;
+}
+
+static void default_agent_exited(void *data)
+{
+ debug("D-Bus client exited without unregistering the"
+ " default passkey agent");
+
+ default_agent->exited = 1;
+
+ passkey_agent_free(default_agent);
+ default_agent = NULL;
+}
+
+static struct passkey_agent *passkey_agent_new(struct adapter *adapter, DBusConnection *conn,
+ const char *name, const char *path,
+ const char *addr)
+{
+ struct passkey_agent *agent;
+
+ agent = g_new0(struct passkey_agent, 1);
+
+ agent->adapter = adapter;
+
+ agent->name = g_strdup(name);
+ agent->path = g_strdup(path);
+
+ if (addr)
+ agent->addr = g_strdup(addr);
+
+ agent->conn = dbus_connection_ref(conn);
+
+ return agent;
+}
+
+static int agent_cmp(const struct passkey_agent *a, const struct passkey_agent *b)
+{
+ int ret;
+
+ if (b->name) {
+ if (!a->name)
+ return -1;
+ ret = strcmp(a->name, b->name);
+ if (ret)
+ return ret;
+ }
+
+ if (b->path) {
+ if (!a->path)
+ return -1;
+ ret = strcmp(a->path, b->path);
+ if (ret)
+ return ret;
+ }
+
+ if (b->addr) {
+ if (!a->addr)
+ return -1;
+ ret = strcmp(a->addr, b->addr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+}
+
+static DBusMessage *register_passkey_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct passkey_agent *agent, ref;
+ struct adapter *adapter;
+ const char *path, *addr;
+
+ if (!data) {
+ error("register_passkey_agent called without any adapter info!");
+ return NULL;
+ }
+
+ adapter = data;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if ((check_address(addr) < 0) || (path[0] != '/'))
+ return invalid_args(msg);
+
+ memset(&ref, 0, sizeof(ref));
+
+ ref.name = (char *) dbus_message_get_sender(msg);
+ ref.addr = (char *) addr;
+ ref.path = (char *) path;
+
+ if (g_slist_find_custom(adapter->passkey_agents, &ref, (GCompareFunc) agent_cmp))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".AlreadyExists",
+ "Passkey agent already exists");
+
+ agent = passkey_agent_new(adapter, conn, ref.name, path, addr);
+ if (!agent)
+ return NULL;
+
+ /* Only add a name listener if there isn't one already for this name */
+ ref.addr = NULL;
+ ref.path = NULL;
+ if (!g_slist_find_custom(adapter->passkey_agents, &ref,
+ (GCompareFunc) agent_cmp))
+ agent->listener_id = g_dbus_add_disconnect_watch(conn, ref.name,
+ agent_exited, agent, NULL);
+
+ agent->timeout = g_timeout_add(AGENT_TIMEOUT,
+ (GSourceFunc) agent_timeout, agent);
+
+ adapter->passkey_agents = g_slist_append(adapter->passkey_agents, agent);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_passkey_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter;
+ GSList *match;
+ struct passkey_agent ref, *agent;
+ const char *path, *addr;
+
+ if (!data) {
+ error("unregister_passkey_agent called without any adapter info!");
+ return NULL;
+ }
+
+ adapter = data;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ memset(&ref, 0, sizeof(ref));
+
+ ref.name = (char *) dbus_message_get_sender(msg);
+ ref.path = (char *) path;
+ ref.addr = (char *) addr;
+
+ match = g_slist_find_custom(adapter->passkey_agents, &ref, (GCompareFunc) agent_cmp);
+ if (!match)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Passkey agent does not exist");
+
+ agent = match->data;
+
+ g_dbus_remove_watch(agent->conn, agent->listener_id);
+
+ adapter->passkey_agents = g_slist_remove(adapter->passkey_agents, agent);
+ agent->exited = 1;
+ passkey_agent_free(agent);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *register_default_passkey_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+
+ if (default_agent)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".AlreadyExists",
+ "Passkey agent already exists");
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ default_agent = passkey_agent_new(NULL, conn, dbus_message_get_sender(msg),
+ path, NULL);
+ if (!default_agent)
+ goto need_memory;
+
+ default_agent->listener_id = g_dbus_add_disconnect_watch(conn,
+ default_agent->name,
+ default_agent_exited,
+ NULL, NULL);
+
+ info("Default passkey agent (%s, %s) registered",
+ default_agent->name, default_agent->path);
+
+ return dbus_message_new_method_return(msg);
+
+need_memory:
+ if (default_agent) {
+ default_agent->exited = 1;
+ passkey_agent_free(default_agent);
+ default_agent = NULL;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *unregister_default_passkey_agent(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path, *name;
+
+ if (!default_agent)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Passkey agent does not exist");
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ name = dbus_message_get_sender(msg);
+
+ if (strcmp(name, default_agent->name) || strcmp(path, default_agent->path))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Passkey agent does not exist");
+
+ g_dbus_remove_watch(default_agent->conn, default_agent->listener_id);
+
+ info("Default passkey agent (%s, %s) unregistered",
+ default_agent->name, default_agent->path);
+
+ default_agent->exited = 1;
+ passkey_agent_free(default_agent);
+ default_agent = NULL;
+
+ return dbus_message_new_method_return(msg);
+}
+
+static struct auth_agent_req *auth_agent_req_new(struct authorization_agent *agent,
+ const char *adapter_path,
+ const char *address,
+ const char *service_path,
+ const char *uuid,
+ service_auth_cb cb,
+ void *user_data)
+{
+ struct auth_agent_req *req;
+
+ req = g_new0(struct auth_agent_req, 1);
+
+ req->agent = agent;
+ req->adapter_path = g_strdup(adapter_path);
+ req->address = g_strdup(address);
+ req->service_path = g_strdup(service_path);
+ req->uuid = g_strdup(uuid);
+ req->cb = cb;
+ req->user_data = user_data;
+
+ return req;
+}
+
+static void auth_agent_req_free(struct auth_agent_req *req)
+{
+ g_free(req->adapter_path);
+ g_free(req->address);
+ g_free(req->service_path);
+ g_free(req->uuid);
+ if (req->call)
+ dbus_pending_call_unref(req->call);
+ g_free(req);
+}
+
+static void auth_agent_req_cancel(struct auth_agent_req *req)
+{
+ dbus_pending_call_cancel(req->call);
+}
+
+static void auth_agent_cancel_requests(struct authorization_agent *agent)
+{
+ GSList *l;
+
+ for (l = agent->pending_requests; l != NULL; l = l->next) {
+ struct auth_agent_req *req = l->data;
+ auth_agent_req_cancel(req);
+ auth_agent_req_free(req);
+ }
+}
+
+static void auth_agent_call_cancel(struct auth_agent_req *req)
+{
+ struct authorization_agent *agent = req->agent;
+ DBusMessage *message;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.AuthorizationAgent", "Cancel");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &req->adapter_path,
+ DBUS_TYPE_STRING, &req->address,
+ DBUS_TYPE_STRING, &req->service_path,
+ DBUS_TYPE_STRING, &req->uuid,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(agent->conn, message, NULL);
+
+ dbus_message_unref(message);
+}
+
+static void auth_agent_free(struct authorization_agent *agent)
+{
+ g_free(agent->name);
+ g_free(agent->path);
+ dbus_connection_unref(agent->conn);
+ g_slist_free(agent->pending_requests);
+ g_free(agent);
+}
+
+static struct authorization_agent *auth_agent_new(DBusConnection *conn,
+ const char *name,
+ const char *path)
+{
+ struct authorization_agent *agent;
+
+ agent = g_new0(struct authorization_agent, 1);
+
+ agent->name = g_strdup(name);
+ agent->path = g_strdup(path);
+
+ agent->conn = dbus_connection_ref(conn);
+
+ return agent;
+}
+
+static void default_auth_agent_exited(void *data)
+{
+ debug("D-Bus client exited without unregistering the "
+ "default authorization agent");
+
+ auth_agent_cancel_requests(default_auth_agent);
+ auth_agent_free(default_auth_agent);
+ default_auth_agent = NULL;
+}
+
+static void auth_agent_release(struct authorization_agent *agent)
+{
+ DBusMessage *message;
+
+ debug("Releasing authorization agent %s, %s",
+ agent->name, agent->path);
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.AuthorizationAgent", "Release");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(agent->conn, message, NULL);
+
+ dbus_message_unref(message);
+
+ if (agent == default_auth_agent)
+ g_dbus_remove_watch(agent->conn, agent->listener_id);
+}
+
+static DBusMessage *register_default_auth_agent(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ const char *path;
+
+ if (default_auth_agent)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".AlreadyExists",
+ "Authorization agent already exists");
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ default_auth_agent = auth_agent_new(conn,
+ dbus_message_get_sender(msg), path);
+ if (!default_auth_agent)
+ goto need_memory;
+
+ default_auth_agent->listener_id = g_dbus_add_disconnect_watch(conn,
+ default_auth_agent->name,
+ default_auth_agent_exited,
+ NULL, NULL);
+
+ info("Default authorization agent (%s, %s) registered",
+ default_auth_agent->name, default_auth_agent->path);
+
+ return dbus_message_new_method_return(msg);
+
+need_memory:
+ if (default_auth_agent) {
+ auth_agent_free(default_auth_agent);
+ default_auth_agent = NULL;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *unregister_default_auth_agent(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ const char *path, *name;
+
+ if (!default_auth_agent)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Authorization agent does not exist");
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ name = dbus_message_get_sender(msg);
+
+ if (strcmp(name, default_auth_agent->name) ||
+ strcmp(path, default_auth_agent->path))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".DoesNotExist",
+ "Authorization agent does not exist");
+
+ g_dbus_remove_watch(default_auth_agent->conn,
+ default_auth_agent->listener_id);
+
+ info("Default authorization agent (%s, %s) unregistered",
+ default_auth_agent->name, default_auth_agent->path);
+
+ auth_agent_cancel_requests(default_auth_agent);
+ auth_agent_free(default_auth_agent);
+ default_auth_agent = NULL;
+
+ return dbus_message_new_method_return(msg);
+}
+
+static void auth_agent_req_reply(DBusPendingCall *call, void *data)
+{
+ struct auth_agent_req *req = data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError err;
+
+ debug("authorize reply");
+
+ dbus_error_init(&err);
+ dbus_set_error_from_message(&err, reply);
+ req->cb(&err, req->user_data);
+
+ default_auth_agent->pending_requests =
+ g_slist_remove(default_auth_agent->pending_requests, req);
+ auth_agent_req_free(req);
+
+ debug("auth_agent_reply: returning");
+}
+
+static DBusPendingCall *auth_agent_call_authorize(struct authorization_agent *agent,
+ const char *adapter_path,
+ const char *service_path,
+ const char *address,
+ const char *uuid)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.AuthorizationAgent", "Authorize");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &adapter_path,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &service_path,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(agent->conn, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+ return call;
+}
+
+int handle_authorize_request_old(struct service *service, const char *path,
+ const char *address, const char *uuid,
+ service_auth_cb cb, void *user_data)
+{
+ struct auth_agent_req *req;
+
+ if (!default_auth_agent) {
+ debug("no default agent");
+ return -EPERM;
+ }
+
+ req = auth_agent_req_new(default_auth_agent, path,
+ address, service->object_path,
+ uuid, cb, user_data);
+
+ req->call = auth_agent_call_authorize(default_auth_agent, path,
+ service->object_path, address, uuid);
+ if (!req->call) {
+ auth_agent_req_free(req);
+ return -ENOMEM;
+ }
+
+ dbus_pending_call_set_notify(req->call, auth_agent_req_reply, req,
+ NULL);
+ default_auth_agent->pending_requests =
+ g_slist_append(default_auth_agent->pending_requests, req);
+
+ debug("authorize request was forwarded");
+
+ return 0;
+}
+
+static int auth_agent_send_cancel(struct authorization_agent *agent,
+ const char *adapter_path,
+ const char *address)
+{
+ struct auth_agent_req *req = NULL;
+ GSList *l;
+
+ for (l = agent->pending_requests; l != NULL; l = l->next) {
+ req = l->data;
+ if (!strcmp(adapter_path, req->adapter_path) &&
+ !strcmp(address, req->address))
+ break;
+ }
+
+ if (!req)
+ return -EIO;
+
+ auth_agent_call_cancel(req);
+ auth_agent_req_cancel(req);
+ agent->pending_requests = g_slist_remove(agent->pending_requests, req);
+ auth_agent_req_free(req);
+
+ return 0;
+}
+
+int cancel_authorize_request_old(const char *path, const char *address)
+{
+ if (!default_auth_agent)
+ return -EIO;
+
+ return auth_agent_send_cancel(default_auth_agent, path, address);
+}
+
+static GDBusMethodTable security_methods[] = {
+ { "RegisterDefaultPasskeyAgent", "s", "",
+ register_default_passkey_agent },
+ { "UnregisterDefaultPasskeyAgent", "s", "",
+ unregister_default_passkey_agent},
+ { "RegisterPasskeyAgent", "ss", "",
+ register_passkey_agent },
+ { "UnregisterPasskeyAgent", "ss", "",
+ unregister_passkey_agent },
+ { "RegisterDefaultAuthorizationAgent", "s", "",
+ register_default_auth_agent },
+ { "UnregisterDefaultAuthorizationAgent","s", "",
+ unregister_default_auth_agent },
+ { }
+};
+
+dbus_bool_t security_init(DBusConnection *conn, const char *path)
+{
+ return g_dbus_register_interface(conn, path, SECURITY_INTERFACE,
+ security_methods, NULL, NULL, NULL, NULL);
+}
+
+dbus_bool_t security_cleanup(DBusConnection *conn, const char *path)
+{
+ return g_dbus_unregister_interface(conn, path, SECURITY_INTERFACE);
+}
+
+static DBusPendingCall *agent_request(const char *path, bdaddr_t *bda,
+ struct passkey_agent *agent,
+ dbus_bool_t numeric, int old_if)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+ char bda_str[18], *ptr = bda_str;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.PasskeyAgent", "Request");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ ba2str(bda, bda_str);
+
+ if (old_if)
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+ else
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_BOOLEAN, &numeric,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_connection_send_with_reply(agent->conn, message,
+ &call, REQUEST_TIMEOUT) == FALSE) {
+ error("D-Bus send failed");
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+ return call;
+}
+
+static void passkey_agent_reply(DBusPendingCall *call, void *user_data)
+{
+ struct pending_agent_request *req = user_data;
+ struct passkey_agent *agent = req->agent;
+ struct adapter *adapter = manager_find_adapter(&req->sba);
+ pin_code_reply_cp pr;
+ DBusMessage *message;
+ DBusError err;
+ size_t len;
+ char *pin;
+
+ /* steal_reply will always return non-NULL since the callback
+ * is only called after a reply has been received */
+ message = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+ if (!req->old_if && !strcmp(err.name, DBUS_ERROR_UNKNOWN_METHOD)) {
+ debug("New Request API failed, trying old one");
+ req->old_if = 1;
+ dbus_error_free(&err);
+ dbus_pending_call_unref(req->call);
+ req->call = agent_request(req->path, &req->bda, agent,
+ FALSE, 1);
+ if (!req->call)
+ goto fail;
+
+ dbus_message_unref(message);
+
+ dbus_pending_call_set_notify(req->call,
+ passkey_agent_reply,
+ req, NULL);
+ return;
+ }
+
+ error("Passkey agent replied with an error: %s, %s",
+ err.name, err.message);
+
+ dbus_error_free(&err);
+ goto fail;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(message, &err,
+ DBUS_TYPE_STRING, &pin,
+ DBUS_TYPE_INVALID)) {
+ error("Wrong passkey reply signature: %s", err.message);
+ dbus_error_free(&err);
+ goto fail;
+ }
+
+ len = strlen(pin);
+
+ if (len > 16 || len < 1) {
+ error("Invalid passkey length from handler");
+ goto fail;
+ }
+
+ set_pin_length(&req->sba, len);
+
+ memset(&pr, 0, sizeof(pr));
+ bacpy(&pr.bdaddr, &req->bda);
+ memcpy(pr.pin_code, pin, len);
+ pr.pin_len = len;
+ hci_send_cmd(req->dev, OGF_LINK_CTL,
+ OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr);
+
+ goto done;
+
+fail:
+ hci_send_cmd(req->dev, OGF_LINK_CTL,
+ OCF_PIN_CODE_NEG_REPLY, 6, &req->bda);
+
+done:
+ if (adapter)
+ adapter_auth_request_replied(adapter, &req->bda);
+
+ if (message)
+ dbus_message_unref(message);
+
+ agent->pending_requests = g_slist_remove(agent->pending_requests, req);
+ dbus_pending_call_cancel(req->call);
+ if (req->call)
+ dbus_pending_call_unref(req->call);
+ g_free(req->path);
+ g_free(req);
+
+ if (agent != default_agent) {
+ agent->adapter->passkey_agents = g_slist_remove(agent->adapter->passkey_agents,
+ agent);
+ passkey_agent_free(agent);
+ }
+}
+
+static int call_passkey_agent(DBusConnection *conn,
+ struct passkey_agent *agent, int dev,
+ const char *path, bdaddr_t *sba,
+ bdaddr_t *dba)
+{
+ struct pending_agent_request *req;
+ struct adapter *adapter = manager_find_adapter(sba);
+
+ if (!agent) {
+ debug("call_passkey_agent(): no agent available");
+ goto send;
+ }
+
+ debug("Calling PasskeyAgent.Request: name=%s, path=%s",
+ agent->name, agent->path);
+
+ req = g_new0(struct pending_agent_request, 1);
+ req->dev = dev;
+ bacpy(&req->sba, sba);
+ bacpy(&req->bda, dba);
+ req->agent = agent;
+ req->path = g_strdup(path);
+
+ req->call = agent_request(path, dba, agent, FALSE, 0);
+ if (!req->call)
+ goto failed;
+
+ dbus_pending_call_set_notify(req->call, passkey_agent_reply, req, NULL);
+
+ agent->pending_requests = g_slist_append(agent->pending_requests, req);
+
+ return 0;
+
+failed:
+ g_free(req->path);
+ g_free(req);
+
+send:
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba);
+
+ if (adapter)
+ adapter_auth_request_replied(adapter, dba);
+
+ return -1;
+}
+
+int handle_passkey_request_old(DBusConnection *conn, int dev,
+ struct adapter *adapter,
+ bdaddr_t *sba, bdaddr_t *dba)
+{
+ struct passkey_agent *agent = default_agent;
+ GSList *l;
+ char addr[18];
+
+ ba2str(dba, addr);
+
+ for (l = adapter->passkey_agents; l != NULL; l = l->next) {
+ struct passkey_agent *a = l->data;
+ if (a != default_agent && g_slist_length(a->pending_requests) >= 1)
+ continue;
+ if (!strcmp(a->addr, addr)) {
+ agent = a;
+ break;
+ }
+ }
+
+ return call_passkey_agent(conn, agent, dev, adapter->path, sba, dba);
+}
+
+static void send_cancel_request(struct pending_agent_request *req)
+{
+ DBusMessage *message;
+ char address[18], *ptr = address;
+
+ message = dbus_message_new_method_call(req->agent->name, req->agent->path,
+ "org.bluez.PasskeyAgent", "Cancel");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ ba2str(&req->bda, address);
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &req->path,
+ DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(req->agent->conn, message, NULL);
+
+ dbus_message_unref(message);
+
+ debug("PasskeyAgent.Request(%s, %s) was canceled", req->path, address);
+
+ dbus_pending_call_cancel(req->call);
+ dbus_pending_call_unref(req->call);
+ g_free(req->pin);
+ g_free(req->path);
+ g_free(req);
+}
+
+static void release_agent(struct passkey_agent *agent)
+{
+ DBusMessage *message;
+
+ debug("Releasing agent %s, %s", agent->name, agent->path);
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.PasskeyAgent", "Release");
+ if (message == NULL) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ dbus_message_set_no_reply(message, TRUE);
+
+ dbus_connection_send(agent->conn, message, NULL);
+
+ dbus_message_unref(message);
+
+ if (agent == default_agent)
+ g_dbus_remove_watch(agent->conn, agent->listener_id);
+ else {
+ struct passkey_agent ref;
+
+ /* Only remove the name listener if there are no more agents
+ * for this name */
+ memset(&ref, 0, sizeof(ref));
+ ref.name = agent->name;
+ if (!g_slist_find_custom(agent->adapter->passkey_agents, &ref,
+ (GCompareFunc) agent_cmp))
+ g_dbus_remove_watch(agent->conn, agent->listener_id);
+ }
+}
+
+void release_default_agent_old(void)
+{
+ if (!default_agent)
+ return;
+
+ passkey_agent_free(default_agent);
+ default_agent = NULL;
+}
+
+void release_default_auth_agent(void)
+{
+ if (!default_auth_agent)
+ return;
+
+ auth_agent_cancel_requests(default_auth_agent);
+ auth_agent_release(default_auth_agent);
+
+ auth_agent_free(default_auth_agent);
+ default_auth_agent = NULL;
+}
+
+void release_passkey_agents(struct adapter *adapter, bdaddr_t *bda)
+{
+ GSList *l, *next;
+
+ for (l = adapter->passkey_agents; l != NULL; l = next) {
+ struct passkey_agent *agent = l->data;
+ next = l->next;
+
+ if (bda && agent->addr) {
+ bdaddr_t tmp;
+ str2ba(agent->addr, &tmp);
+ if (bacmp(&tmp, bda))
+ continue;
+ }
+
+ adapter->passkey_agents = g_slist_remove(adapter->passkey_agents, agent);
+ passkey_agent_free(agent);
+ }
+}
+
+void cancel_passkey_agent_requests(GSList *agents, const char *path,
+ bdaddr_t *addr)
+{
+ GSList *l, *next;
+
+ /* First check the default agent */
+ for (l = default_agent ? default_agent->pending_requests : NULL; l != NULL; l = next) {
+ struct pending_agent_request *req = l->data;
+ next = l->next;
+ if (!strcmp(path, req->path) && (!addr || !bacmp(addr, &req->bda))) {
+ send_cancel_request(req);
+ default_agent->pending_requests = g_slist_remove(default_agent->pending_requests,
+ req);
+ }
+ }
+
+ /* and then the adapter specific agents */
+ for (; agents != NULL; agents = agents->next) {
+ struct passkey_agent *agent = agents->data;
+
+ for (l = agent->pending_requests; l != NULL; l = next) {
+ struct pending_agent_request *req = l->data;
+ next = l->next;
+ if (!strcmp(path, req->path) && (!addr || !bacmp(addr, &req->bda))) {
+ send_cancel_request(req);
+ agent->pending_requests = g_slist_remove(agent->pending_requests, req);
+ }
+ }
+ }
+}
diff --git a/utils/hcid/dbus-security.h b/utils/hcid/dbus-security.h
new file mode 100644
index 00000000..8c23417a
--- /dev/null
+++ b/utils/hcid/dbus-security.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define SECURITY_INTERFACE "org.bluez.Security"
+
+dbus_bool_t security_init(DBusConnection *conn, const char *path);
+dbus_bool_t security_cleanup(DBusConnection *conn, const char *path);
+
+int handle_passkey_request_old(DBusConnection *conn, int dev,
+ struct adapter *adapter,
+ bdaddr_t *sba, bdaddr_t *dba);
+
+int handle_confirm_request_old(DBusConnection *conn, int dev,
+ struct adapter *adapter,
+ bdaddr_t *sba, bdaddr_t *dba,
+ const char *pin);
+
+void release_default_agent_old(void);
+
+void release_default_auth_agent(void);
+
+void release_passkey_agents(struct adapter *adapter, bdaddr_t *bda);
+
+void cancel_passkey_agent_requests(GSList *agents, const char *path, bdaddr_t *dba);
+
+int handle_authorize_request_old(struct service *service, const char *path,
+ const char *address, const char *uuid,
+ service_auth_cb cb, void *user_data);
+int cancel_authorize_request_old(const char *path, const char *address);
diff --git a/utils/hcid/dbus-service.c b/utils/hcid/dbus-service.c
new file mode 100644
index 00000000..d07741a3
--- /dev/null
+++ b/utils/hcid/dbus-service.c
@@ -0,0 +1,746 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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 <dirent.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "server.h"
+#include "dbus-common.h"
+#include "error.h"
+#include "manager.h"
+#include "adapter.h"
+#include "agent.h"
+#include "device.h"
+#include "dbus-service.h"
+#include "dbus-hci.h"
+#include "dbus-security.h"
+
+#define SERVICE_INTERFACE "org.bluez.Service"
+
+struct service_uuids {
+ char *name;
+ char **uuids;
+};
+
+struct service_auth {
+ service_auth_cb cb;
+ void *user_data;
+};
+
+static GSList *services = NULL;
+static GSList *services_uuids = NULL;
+
+static void service_free(struct service *service)
+{
+ if (!service)
+ return;
+
+ g_free(service->object_path);
+ g_free(service->ident);
+ g_free(service->name);
+
+ g_free(service);
+}
+
+static DBusMessage *get_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct service *service = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dbus_message_iter_append_dict_entry(&dict, "identifier",
+ DBUS_TYPE_STRING, &service->ident);
+
+ dbus_message_iter_append_dict_entry(&dict, "name",
+ DBUS_TYPE_STRING, &service->name);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *get_identifier(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+
+ struct service *service = data;
+ DBusMessage *reply;
+ const char *identifier = "";
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (service->ident)
+ identifier = service->ident;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &identifier,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *get_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+
+ struct service *service = data;
+ DBusMessage *reply;
+ const char *name = "";
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (service->name)
+ name = service->name;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *get_description(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *description = "";
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &description,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *get_bus_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *busname = "org.bluez";
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &busname,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *start(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ strerror(EALREADY));
+}
+
+static DBusMessage *stop(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ strerror(EPERM));
+}
+
+static DBusMessage *is_running(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ dbus_bool_t running = TRUE;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_BOOLEAN, &running,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *is_external(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ dbus_bool_t external = TRUE;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_BOOLEAN, &external,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+}
+
+static DBusMessage *set_trusted(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct service *service = data;
+ const char *address;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ write_trust(BDADDR_ANY, address, service->ident, TRUE);
+
+ g_dbus_emit_signal(conn, service->object_path,
+ SERVICE_INTERFACE, "TrustAdded",
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *list_trusted(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct service *service = data;
+ DBusMessage *reply;
+ GSList *trusts, *l;
+ char **addrs;
+ int len;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ trusts = list_trusts(BDADDR_ANY, service->ident);
+
+ addrs = g_new(char *, g_slist_length(trusts));
+
+ for (l = trusts, len = 0; l; l = l->next, len++)
+ addrs[len] = l->data;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &addrs, len, DBUS_TYPE_INVALID);
+
+ g_free(addrs);
+ g_slist_foreach(trusts, (GFunc) g_free, NULL);
+ g_slist_free(trusts);
+
+ return reply;
+}
+
+static DBusMessage *is_trusted(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct service *service = data;
+ DBusMessage *reply;
+ const char *address;
+ dbus_bool_t trusted;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ trusted = read_trust(BDADDR_ANY, address, service->ident);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_BOOLEAN, &trusted,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *remove_trust(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct service *service = data;
+ const char *address;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ if (check_address(address) < 0)
+ return invalid_args(msg);
+
+ write_trust(BDADDR_ANY, address, service->ident, FALSE);
+
+ g_dbus_emit_signal(conn, service->object_path,
+ SERVICE_INTERFACE, "TrustRemoved",
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable service_methods[] = {
+ { "GetInfo", "", "a{sv}", get_info },
+ { "GetIdentifier", "", "s", get_identifier },
+ { "GetName", "", "s", get_name },
+ { "GetDescription", "", "s", get_description },
+ { "GetBusName", "", "s", get_bus_name },
+ { "Start", "", "", start },
+ { "Stop", "", "", stop },
+ { "IsRunning", "", "b", is_running },
+ { "IsExternal", "", "b", is_external },
+ { "SetTrusted", "s", "", set_trusted },
+ { "IsTrusted", "s", "b", is_trusted },
+ { "RemoveTrust", "s", "", remove_trust },
+ { "ListTrusts", "", "as", list_trusted },
+ { NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable service_signals[] = {
+ { "Started", "" },
+ { "Stopped", "" },
+ { "TrustAdded", "s" },
+ { "TrustRemoved", "s" },
+ { NULL, NULL }
+};
+
+static int service_cmp_path(struct service *service, const char *path)
+{
+ return strcmp(service->object_path, path);
+}
+
+static int service_cmp_ident(struct service *service, const char *ident)
+{
+ return strcmp(service->ident, ident);
+}
+
+static int unregister_service_for_connection(DBusConnection *connection,
+ struct service *service)
+{
+ DBusConnection *conn = get_dbus_connection();
+
+ debug("Unregistering service object: %s", service->object_path);
+
+ if (!conn)
+ goto cleanup;
+
+ g_dbus_emit_signal(conn, service->object_path,
+ SERVICE_INTERFACE,
+ "Stopped", DBUS_TYPE_INVALID);
+
+ g_dbus_emit_signal(conn, BASE_PATH, MANAGER_INTERFACE,
+ "ServiceRemoved",
+ DBUS_TYPE_STRING, &service->object_path,
+ DBUS_TYPE_INVALID);
+
+ if (!g_dbus_unregister_interface(conn,
+ service->object_path, SERVICE_INTERFACE)) {
+ error("D-Bus failed to unregister %s object",
+ service->object_path);
+ return -1;
+ }
+
+cleanup:
+ services = g_slist_remove(services, service);
+ service_free(service);
+
+ return 0;
+}
+
+static int do_unregister(struct service *service)
+{
+ DBusConnection *conn = get_dbus_connection();
+
+ return unregister_service_for_connection(conn, service);
+}
+
+void release_services(DBusConnection *conn)
+{
+ debug("release_services");
+
+ g_slist_foreach(services, (GFunc) do_unregister, NULL);
+ g_slist_free(services);
+ services = NULL;
+}
+
+struct service *search_service(const char *pattern)
+{
+ GSList *l;
+ const char *bus_id;
+
+ /* Workaround for plugins: share the same bus id */
+ bus_id = dbus_bus_get_unique_name(get_dbus_connection());
+ if (!strcmp(bus_id, pattern))
+ return NULL;
+
+ for (l = services; l != NULL; l = l->next) {
+ struct service *service = l->data;
+
+ if (service->ident && !strcmp(service->ident, pattern))
+ return service;
+ }
+
+ return NULL;
+}
+
+void append_available_services(DBusMessageIter *array_iter)
+{
+ GSList *l;
+
+ for (l = services; l != NULL; l = l->next) {
+ struct service *service = l->data;
+
+ dbus_message_iter_append_basic(array_iter,
+ DBUS_TYPE_STRING, &service->object_path);
+ }
+}
+
+int service_unregister(DBusConnection *conn, struct service *service)
+{
+ return unregister_service_for_connection(conn, service);
+}
+
+static gint name_cmp(struct service_uuids *su, const char *name)
+{
+ return strcmp(su->name, name);
+}
+
+static gint uuid_cmp(struct service_uuids *su, const char *uuid)
+{
+ int i;
+
+ for (i = 0; su->uuids[i]; i++) {
+ if (!strcasecmp(su->uuids[i], uuid))
+ return 0;
+ }
+
+ return -1;
+}
+
+struct service *search_service_by_uuid(const char *uuid)
+{
+ struct service_uuids *su;
+ struct service *service;
+ GSList *l;
+
+ if (!services_uuids)
+ return NULL;
+
+ l = g_slist_find_custom(services_uuids, uuid, (GCompareFunc) uuid_cmp);
+ if (!l)
+ return NULL;
+
+ su = l->data;
+ service = search_service(su->name);
+ if (!service)
+ return NULL;
+
+ return service;
+}
+
+static void register_uuids(const char *ident, const char **uuids)
+{
+ struct service_uuids *su;
+ int i;
+
+ if (!ident)
+ return;
+
+ su = g_new0(struct service_uuids, 1);
+ su->name = g_strdup(ident);
+
+ for (i = 0; uuids[i]; i++);
+
+ su->uuids = g_new0(char *, i + 1);
+
+ for (i = 0; uuids[i]; i++)
+ su->uuids[i] = g_strdup(uuids[i]);
+
+ services_uuids = g_slist_append(services_uuids, su);
+}
+
+static void service_uuids_free(struct service_uuids *su)
+{
+ int i;
+
+ if (!su)
+ return;
+
+ g_free(su->name);
+
+ for (i = 0; su->uuids[i]; i++)
+ g_free(su->uuids[i]);
+
+ g_free(su);
+}
+
+static void unregister_uuids(const char *ident)
+{
+ struct service_uuids *su;
+ GSList *l;
+
+ if (!services_uuids)
+ return;
+
+ l = g_slist_find_custom(services_uuids, ident, (GCompareFunc) name_cmp);
+ if (!l)
+ return;
+
+ su = l->data;
+ services_uuids = g_slist_remove(services_uuids, su);
+
+ service_uuids_free(su);
+}
+
+static struct service *create_external_service(const char *ident)
+{
+ struct service *service;
+ const char *name;
+
+ service = g_try_new0(struct service, 1);
+ if (!service) {
+ error("OOM while allocating new external service");
+ return NULL;
+ }
+
+ if (!strcmp(ident, "input"))
+ name = "Input service";
+ else if (!strcmp(ident, "audio"))
+ name = "Audio service";
+ else if (!strcmp(ident, "network"))
+ name = "Network service";
+ else if (!strcmp(ident, "serial"))
+ name = "Serial service";
+ else
+ name = "";
+
+ service->ident = g_strdup(ident);
+ service->name = g_strdup(name);
+
+ return service;
+}
+
+int register_service(const char *ident, const char **uuids)
+{
+ DBusConnection *conn = get_dbus_connection();
+ struct service *service;
+ char obj_path[PATH_MAX];
+ int i;
+
+ if (g_slist_find_custom(services, ident,
+ (GCompareFunc) service_cmp_ident))
+ return -EADDRINUSE;
+
+ snprintf(obj_path, sizeof(obj_path) - 1,
+ "/org/bluez/service_%s", ident);
+
+ /* Make the path valid for D-Bus */
+ for (i = strlen("/org/bluez/"); obj_path[i]; i++) {
+ if (!isalnum(obj_path[i]))
+ obj_path[i] = '_';
+ }
+
+ if (g_slist_find_custom(services, obj_path,
+ (GCompareFunc) service_cmp_path))
+ return -EADDRINUSE;
+
+ service = create_external_service(ident);
+
+ debug("Registering service object: %s (%s)",
+ service->ident, obj_path);
+
+ if (!g_dbus_register_interface(conn, obj_path, SERVICE_INTERFACE,
+ service_methods, service_signals,
+ NULL, service, NULL)) {
+ error("D-Bus failed to register %s object", obj_path);
+ service_free(service);
+ return -1;
+ }
+
+ service->object_path = g_strdup(obj_path);
+
+ services = g_slist_append(services, service);
+
+ if (uuids)
+ register_uuids(ident, uuids);
+
+ g_dbus_emit_signal(conn, BASE_PATH, MANAGER_INTERFACE,
+ "ServiceAdded",
+ DBUS_TYPE_STRING, &service->object_path,
+ DBUS_TYPE_INVALID);
+
+ g_dbus_emit_signal(conn, service->object_path,
+ SERVICE_INTERFACE,
+ "Started", DBUS_TYPE_INVALID);
+
+ return 0;
+}
+
+void unregister_service(const char *ident)
+{
+ unregister_uuids(ident);
+}
+
+static void agent_auth_cb(struct agent *agent, DBusError *derr, void *user_data)
+{
+ struct service_auth *auth = user_data;
+
+ auth->cb(derr, auth->user_data);
+
+ g_free(auth);
+}
+
+int service_req_auth(const bdaddr_t *src, const bdaddr_t *dst,
+ const char *uuid, service_auth_cb cb, void *user_data)
+{
+ struct service_auth *auth;
+ struct adapter *adapter;
+ struct device *device;
+ struct agent *agent;
+ struct service *service;
+ char address[18];
+ gboolean trusted;
+
+ adapter = manager_find_adapter(src);
+ if (!adapter)
+ return -EPERM;
+
+ /* Device connected? */
+ if (!g_slist_find_custom(adapter->active_conn,
+ dst, active_conn_find_by_bdaddr))
+ return -ENOTCONN;
+
+ service = search_service_by_uuid(uuid);
+ if (!service)
+ return -EPERM;
+
+ ba2str(dst, address);
+ trusted = read_trust(src, address, GLOBAL_TRUST);
+ if (!trusted)
+ trusted = read_trust(BDADDR_ANY, address, service->ident);
+
+ if (trusted) {
+ cb(NULL, user_data);
+ return 0;
+ }
+
+ device = adapter_find_device(adapter, address);
+ if (!device)
+ return handle_authorize_request_old(service, adapter->path,
+ address, uuid, cb, user_data);
+
+ agent = (device->agent ? : adapter->agent);
+ if (!agent)
+ return handle_authorize_request_old(service, adapter->path,
+ address, uuid, cb, user_data);
+
+ auth = g_try_new0(struct service_auth, 1);
+ if (!auth)
+ return -ENOMEM;
+
+ auth->cb = cb;
+ auth->user_data = user_data;
+
+ return agent_authorize(agent, device->path, uuid, agent_auth_cb, auth);
+}
+
+int service_cancel_auth(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct adapter *adapter = manager_find_adapter(src);
+ struct device *device;
+ struct agent *agent;
+ char address[18];
+
+ if (!adapter)
+ return -EPERM;
+
+ ba2str(dst, address);
+ device = adapter_find_device(adapter, address);
+ if (!device)
+ return -EPERM;
+
+ /*
+ * FIXME: Cancel fails if authorization is requested to adapter's
+ * agent and in the meanwhile CreatePairedDevice is called.
+ */
+
+ agent = (device->agent ? : adapter->agent);
+ if (!agent)
+ return cancel_authorize_request_old(adapter->path, address);
+
+ return agent_cancel(agent);
+}
diff --git a/utils/hcid/dbus-service.h b/utils/hcid/dbus-service.h
new file mode 100644
index 00000000..d41a170a
--- /dev/null
+++ b/utils/hcid/dbus-service.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct service {
+ char *object_path;
+ char *ident;
+ char *name;
+};
+
+void release_services(DBusConnection *conn);
+
+void append_available_services(DBusMessageIter *iter);
+
+struct service *search_service(const char *pattern);
+
+struct service *search_service_by_uuid(const char *uuid);
+
+int service_unregister(DBusConnection *conn, struct service *service);
+
+int register_service(const char *ident, const char **uuids);
+void unregister_service(const char *ident);
+
+typedef void (*service_auth_cb) (DBusError *derr, void *user_data);
+int service_req_auth(const bdaddr_t *src, const bdaddr_t *dst,
+ const char *uuid, service_auth_cb cb, void *user_data);
+int service_cancel_auth(const bdaddr_t *src, const bdaddr_t *dst);
diff --git a/utils/hcid/device.c b/utils/hcid/device.c
new file mode 100644
index 00000000..66ab2dd7
--- /dev/null
+++ b/utils/hcid/device.c
@@ -0,0 +1,1601 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 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 <stdarg.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "sdpd.h"
+
+#include "logging.h"
+#include "textfile.h"
+#include "oui.h"
+
+#include "adapter.h"
+#include "device.h"
+#include "dbus-common.h"
+#include "dbus-hci.h"
+#include "dbus-service.h"
+#include "error.h"
+#include "glib-helper.h"
+#include "agent.h"
+#include "dbus-sdp.h"
+#include "sdp-xml.h"
+
+#define MAX_DEVICES 16
+#define DISCONNECT_TIMER 2
+
+#define DEVICE_INTERFACE "org.bluez.Device"
+
+struct browse_req {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ struct device *device;
+ GSList *uuids_added;
+ GSList *uuids_removed;
+ int search_uuid;
+ gboolean browse;
+};
+
+struct hci_peer {
+ struct timeval lastseen;
+ struct timeval lastused;
+
+ bdaddr_t bdaddr;
+ uint32_t class;
+ int8_t rssi;
+ uint8_t data[240];
+ uint8_t name[248];
+
+ uint8_t pscan_rep_mode;
+ uint8_t pscan_period_mode;
+ uint8_t pscan_mode;
+ uint16_t clock_offset;
+
+ struct hci_peer *next;
+};
+
+struct hci_conn {
+ bdaddr_t bdaddr;
+ uint16_t handle;
+
+ struct hci_conn *next;
+};
+
+struct hci_dev {
+ int ignore;
+
+ bdaddr_t bdaddr;
+ uint8_t features[8];
+ uint8_t lmp_ver;
+ uint16_t lmp_subver;
+ uint16_t hci_rev;
+ uint16_t manufacturer;
+
+ uint8_t ssp_mode;
+ uint8_t name[248];
+ uint8_t class[3];
+
+ struct hci_peer *peers;
+ struct hci_conn *conns;
+};
+
+static struct hci_dev devices[MAX_DEVICES];
+
+#define ASSERT_DEV_ID { if (dev_id >= MAX_DEVICES) return -ERANGE; }
+
+static GSList *drivers = NULL;
+
+static uint16_t uuid_list[] = {
+ PUBLIC_BROWSE_GROUP,
+ HID_SVCLASS_ID,
+ GENERIC_AUDIO_SVCLASS_ID,
+ ADVANCED_AUDIO_SVCLASS_ID,
+ AV_REMOTE_SVCLASS_ID,
+ 0
+};
+
+void init_adapters(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_DEVICES; i++)
+ memset(devices + i, 0, sizeof(struct hci_dev));
+}
+
+static int device_read_bdaddr(uint16_t dev_id, bdaddr_t *bdaddr)
+{
+ int dd, err;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ err = errno;
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ return -err;
+ }
+
+ if (hci_read_bd_addr(dd, bdaddr, 2000) < 0) {
+ err = errno;
+ error("Can't read address for hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+int add_adapter(uint16_t dev_id)
+{
+ struct hci_dev *dev;
+ struct hci_dev_info di;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ if (hci_devinfo(dev_id, &di) < 0) {
+ dev->ignore = 1;
+ return -errno;
+ }
+
+ if (hci_test_bit(HCI_RAW, &di.flags)) {
+ info("Device hci%d is using raw mode", dev_id);
+ dev->ignore = 1;
+ }
+
+ if (bacmp(&di.bdaddr, BDADDR_ANY))
+ bacpy(&dev->bdaddr, &di.bdaddr);
+ else {
+ int err = device_read_bdaddr(dev_id, &dev->bdaddr);
+ if (err < 0)
+ return err;
+ }
+ memcpy(dev->features, di.features, 8);
+
+ info("Device hci%d has been added", dev_id);
+
+ return 0;
+}
+
+int remove_adapter(uint16_t dev_id)
+{
+ struct hci_dev *dev;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ memset(dev, 0, sizeof(struct hci_dev));
+
+ info("Device hci%d has been removed", dev_id);
+
+ return 0;
+}
+
+static inline uint8_t get_inquiry_mode(struct hci_dev *dev)
+{
+ if (dev->features[6] & LMP_EXT_INQ)
+ return 2;
+
+ if (dev->features[3] & LMP_RSSI_INQ)
+ return 1;
+
+ if (dev->manufacturer == 11 &&
+ dev->hci_rev == 0x00 && dev->lmp_subver == 0x0757)
+ return 1;
+
+ if (dev->manufacturer == 15) {
+ if (dev->hci_rev == 0x03 && dev->lmp_subver == 0x6963)
+ return 1;
+ if (dev->hci_rev == 0x09 && dev->lmp_subver == 0x6963)
+ return 1;
+ if (dev->hci_rev == 0x00 && dev->lmp_subver == 0x6965)
+ return 1;
+ }
+
+ if (dev->manufacturer == 31 &&
+ dev->hci_rev == 0x2005 && dev->lmp_subver == 0x1805)
+ return 1;
+
+ return 0;
+}
+
+static void update_ext_inquiry_response(int dd, struct hci_dev *dev)
+{
+ uint8_t fec = 0, data[240];
+
+ if (!(dev->features[6] & LMP_EXT_INQ))
+ return;
+
+ memset(data, 0, sizeof(data));
+
+ if (dev->ssp_mode > 0)
+ create_ext_inquiry_response((char *) dev->name, data);
+
+ if (hci_write_ext_inquiry_response(dd, fec, data, 2000) < 0)
+ error("Can't write extended inquiry response: %s (%d)",
+ strerror(errno), errno);
+}
+
+int start_adapter(uint16_t dev_id)
+{
+ struct hci_dev *dev;
+ struct hci_version ver;
+ uint8_t features[8], inqmode;
+ uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00 };
+ char name[249];
+ int dd, err;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ if (dev->ignore)
+ return 0;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ err = errno;
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ return -err;
+ }
+
+ if (hci_read_local_version(dd, &ver, 1000) < 0) {
+ err = errno;
+ error("Can't read version info for hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ dev->hci_rev = ver.hci_rev;
+ dev->lmp_ver = ver.lmp_ver;
+ dev->lmp_subver = ver.lmp_subver;
+ dev->manufacturer = ver.manufacturer;
+
+ if (hci_read_local_features(dd, features, 1000) < 0) {
+ err = errno;
+ error("Can't read features for hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ memcpy(dev->features, features, 8);
+
+ if (hci_read_class_of_dev(dd, dev->class, 1000) < 0) {
+ err = errno;
+ error("Can't read class of device on hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ if (hci_read_local_name(dd, sizeof(name), name, 2000) < 0) {
+ err = errno;
+ error("Can't read local name on hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ memcpy(dev->name, name, 248);
+
+ if (!(features[6] & LMP_SIMPLE_PAIR))
+ goto setup;
+
+ if (hcid_dbus_use_experimental()) {
+ if (ioctl(dd, HCIGETAUTHINFO, NULL) < 0 && errno != EINVAL)
+ hci_write_simple_pairing_mode(dd, 0x01, 2000);
+ }
+
+ if (hci_read_simple_pairing_mode(dd, &dev->ssp_mode, 1000) < 0) {
+ err = errno;
+ error("Can't read simple pairing mode on hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+setup:
+ if (ver.hci_rev > 1) {
+ if (features[5] & LMP_SNIFF_SUBR)
+ events[5] |= 0x20;
+
+ if (features[5] & LMP_PAUSE_ENC)
+ events[5] |= 0x80;
+
+ if (features[6] & LMP_EXT_INQ)
+ events[5] |= 0x40;
+
+ if (features[6] & LMP_NFLUSH_PKTS)
+ events[7] |= 0x01;
+
+ if (features[7] & LMP_LSTO)
+ events[6] |= 0x80;
+
+ if (features[6] & LMP_SIMPLE_PAIR) {
+ events[6] |= 0x01; /* IO Capability Request */
+ events[6] |= 0x02; /* IO Capability Response */
+ events[6] |= 0x04; /* User Confirmation Request */
+ events[6] |= 0x08; /* User Passkey Request */
+ events[6] |= 0x10; /* Remote OOB Data Request */
+ events[6] |= 0x20; /* Simple Pairing Complete */
+ events[7] |= 0x04; /* User Passkey Notification */
+ events[7] |= 0x08; /* Keypress Notification */
+ events[7] |= 0x10; /* Remote Host Supported Features Notification */
+ }
+
+ hci_send_cmd(dd, OGF_HOST_CTL, OCF_SET_EVENT_MASK,
+ sizeof(events), events);
+ }
+
+ if (read_local_name(&dev->bdaddr, name) == 0) {
+ memcpy(dev->name, name, 248);
+ hci_write_local_name(dd, name, 5000);
+ }
+
+ update_ext_inquiry_response(dd, dev);
+
+ inqmode = get_inquiry_mode(dev);
+ if (inqmode < 1)
+ goto done;
+
+ if (hci_write_inquiry_mode(dd, inqmode, 2000) < 0) {
+ err = errno;
+ error("Can't write inquiry mode for hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+done:
+ hci_close_dev(dd);
+
+ info("Device hci%d has been activated", dev_id);
+
+ return 0;
+}
+
+int stop_adapter(uint16_t dev_id)
+{
+ ASSERT_DEV_ID;
+
+ info("Device hci%d has been disabled", dev_id);
+
+ return 0;
+}
+
+int update_adapter(uint16_t dev_id)
+{
+ struct hci_dev *dev;
+ int dd;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ if (dev->ignore)
+ return 0;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ int err = errno;
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ return -err;
+ }
+
+ update_ext_inquiry_response(dd, dev);
+
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+int get_device_address(uint16_t dev_id, char *address, size_t size)
+{
+ struct hci_dev *dev;
+
+ ASSERT_DEV_ID;
+
+ if (size < 18)
+ return -ENOBUFS;
+
+ dev = &devices[dev_id];
+
+ return ba2str(&dev->bdaddr, address);
+}
+
+int get_device_class(uint16_t dev_id, uint8_t *cls)
+{
+ struct hci_dev *dev;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+ memcpy(cls, dev->class, 3);
+
+ return 0;
+}
+
+int set_device_class(uint16_t dev_id, uint8_t *cls)
+{
+ struct hci_dev *dev;
+
+ ASSERT_DEV_ID;
+ dev = &devices[dev_id];
+ memcpy(dev->class, cls, 3);
+
+ return 0;
+}
+
+int get_device_version(uint16_t dev_id, char *version, size_t size)
+{
+ struct hci_dev *dev;
+ char edr[7], *tmp;
+ int err;
+
+ ASSERT_DEV_ID;
+
+ if (size < 14)
+ return -ENOBUFS;
+
+ dev = &devices[dev_id];
+
+ if ((dev->lmp_ver == 0x03 || dev->lmp_ver == 0x04) &&
+ (dev->features[3] & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M)))
+ sprintf(edr, " + EDR");
+ else
+ edr[0] = '\0';
+
+ tmp = lmp_vertostr(dev->lmp_ver);
+
+ if (strlen(tmp) == 0)
+ err = snprintf(version, size, "not assigned");
+ else
+ err = snprintf(version, size, "Bluetooth %s%s", tmp, edr);
+
+ bt_free(tmp);
+
+ return err;
+}
+
+static int digi_revision(uint16_t dev_id, char *revision, size_t size)
+{
+ struct hci_request rq;
+ unsigned char req[] = { 0x07 };
+ unsigned char buf[102];
+ int dd, err;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ err = errno;
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ return -err;
+ }
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x000e;
+ rq.cparam = req;
+ rq.clen = sizeof(req);
+ rq.rparam = &buf;
+ rq.rlen = sizeof(buf);
+
+ if (hci_send_req(dd, &rq, 2000) < 0) {
+ err = errno;
+ error("Can't read revision for hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ hci_close_dev(dd);
+
+ return snprintf(revision, size, "%s", buf + 1);
+}
+
+int get_device_revision(uint16_t dev_id, char *revision, size_t size)
+{
+ struct hci_dev *dev;
+ int err;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ switch (dev->manufacturer) {
+ case 10:
+ err = snprintf(revision, size, "Build %d", dev->lmp_subver);
+ break;
+ case 12:
+ err = digi_revision(dev_id, revision, size);
+ break;
+ case 15:
+ err = snprintf(revision, size, "%d.%d / %d",
+ dev->hci_rev & 0xff,
+ dev->lmp_subver >> 8, dev->lmp_subver & 0xff);
+ break;
+ default:
+ err = snprintf(revision, size, "0x%02x", dev->lmp_subver);
+ break;
+ }
+
+ return err;
+}
+
+int get_device_manufacturer(uint16_t dev_id, char *manufacturer, size_t size)
+{
+ char *tmp;
+
+ ASSERT_DEV_ID;
+
+ tmp = bt_compidtostr(devices[dev_id].manufacturer);
+
+ return snprintf(manufacturer, size, "%s", tmp);
+}
+
+int get_device_company(uint16_t dev_id, char *company, size_t size)
+{
+ char *tmp, oui[9];
+ int err;
+
+ ASSERT_DEV_ID;
+
+ ba2oui(&devices[dev_id].bdaddr, oui);
+ tmp = ouitocomp(oui);
+
+ err = snprintf(company, size, "%s", tmp);
+
+ free(tmp);
+
+ return err;
+}
+
+int set_simple_pairing_mode(uint16_t dev_id, uint8_t mode)
+{
+ struct hci_dev *dev;
+ int dd;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ dev->ssp_mode = mode;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ int err = errno;
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ return -err;
+ }
+
+ update_ext_inquiry_response(dd, dev);
+
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+int get_device_name(uint16_t dev_id, char *name, size_t size)
+{
+ char tmp[249];
+ int dd, err;
+
+ ASSERT_DEV_ID;
+
+ memset(tmp, 0, sizeof(tmp));
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ err = errno;
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ return -err;
+ }
+
+ if (hci_read_local_name(dd, sizeof(tmp), tmp, 2000) < 0) {
+ err = errno;
+ error("Can't read name for hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ hci_close_dev(dd);
+
+ memcpy(devices[dev_id].name, tmp, 248);
+
+ return snprintf(name, size, "%s", tmp);
+}
+
+int set_device_name(uint16_t dev_id, const char *name)
+{
+ struct hci_dev *dev;
+ int dd, err;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ err = errno;
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ return -err;
+ }
+
+ if (hci_write_local_name(dd, name, 5000) < 0) {
+ err = errno;
+ error("Can't write name for hci%d: %s (%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
+
+ strncpy((char *) dev->name, name, 248);
+
+ update_ext_inquiry_response(dd, dev);
+
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+int get_device_alias(uint16_t dev_id, const bdaddr_t *bdaddr, char *alias, size_t size)
+{
+ char filename[PATH_MAX + 1], addr[18], *tmp;
+ int err;
+
+ ASSERT_DEV_ID;
+
+ ba2str(&devices[dev_id].bdaddr, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "aliases");
+
+ ba2str(bdaddr, addr);
+
+ tmp = textfile_get(filename, addr);
+ if (!tmp)
+ return -ENXIO;
+
+ err = snprintf(alias, size, "%s", tmp);
+
+ free(tmp);
+
+ return err;
+}
+
+int set_device_alias(uint16_t dev_id, const bdaddr_t *bdaddr, const char *alias)
+{
+ char filename[PATH_MAX + 1], addr[18];
+
+ ASSERT_DEV_ID;
+
+ ba2str(&devices[dev_id].bdaddr, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "aliases");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(bdaddr, addr);
+
+ return textfile_put(filename, addr, alias);
+}
+
+int remove_device_alias(uint16_t dev_id, const bdaddr_t *bdaddr)
+{
+ char filename[PATH_MAX + 1], addr[18];
+
+ ASSERT_DEV_ID;
+
+ ba2str(&devices[dev_id].bdaddr, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "aliases");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(bdaddr, addr);
+
+ return textfile_del(filename, addr);
+}
+
+int get_encryption_key_size(uint16_t dev_id, const bdaddr_t *baddr)
+{
+ struct hci_dev *dev;
+ int size;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+
+ switch (dev->manufacturer) {
+ default:
+ size = -ENOENT;
+ break;
+ }
+
+ return size;
+}
+
+static void device_free(gpointer user_data)
+{
+ struct device *device = user_data;
+
+ if (device->agent)
+ agent_destroy(device->agent, FALSE);
+
+ g_slist_foreach(device->uuids, (GFunc) g_free, NULL);
+ g_slist_free(device->uuids);
+
+ if (device->disconn_timer)
+ g_source_remove(device->disconn_timer);
+
+ g_free(device->address);
+ g_free(device->path);
+ g_free(device);
+}
+
+static gboolean device_is_paired(struct device *device)
+{
+ struct adapter *adapter = device->adapter;
+ char filename[PATH_MAX + 1], *str;
+ gboolean ret;
+
+ create_name(filename, PATH_MAX, STORAGEDIR,
+ adapter->address, "linkkeys");
+ str = textfile_caseget(filename, device->address);
+ ret = str ? TRUE : FALSE;
+ g_free(str);
+
+ return ret;
+}
+
+static char *device_get_name(struct device *device)
+{
+ struct adapter *adapter = device->adapter;
+ char filename[PATH_MAX + 1];
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address, "names");
+ return textfile_caseget(filename, device->address);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct device *device = user_data;
+ struct adapter *adapter = device->adapter;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ bdaddr_t src, dst;
+ char path[MAX_PATH_LENGTH];
+ char buf[64];
+ const char *ptr;
+ char *name, *ppath, **uuids;
+ dbus_bool_t boolean;
+ uint32_t class;
+ int i;
+ GSList *l;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ /* Address */
+ dbus_message_iter_append_dict_entry(&dict, "Address", DBUS_TYPE_STRING,
+ &device->address);
+
+ /* Name */
+ name = device_get_name(device);
+ if (name) {
+ dbus_message_iter_append_dict_entry(&dict, "Name",
+ DBUS_TYPE_STRING, &name);
+ }
+
+ str2ba(adapter->address, &src);
+ str2ba(device->address, &dst);
+
+ /* Class */
+ if (read_remote_class(&src, &dst, &class) == 0) {
+ dbus_message_iter_append_dict_entry(&dict, "Class",
+ DBUS_TYPE_UINT32, &class);
+ }
+
+ /* Alias */
+ if (get_device_alias(adapter->dev_id, &dst, buf, sizeof(buf)) > 0) {
+ ptr = buf;
+ dbus_message_iter_append_dict_entry(&dict, "Alias",
+ DBUS_TYPE_STRING, &ptr);
+ } else if (name) {
+ dbus_message_iter_append_dict_entry(&dict, "Alias",
+ DBUS_TYPE_STRING, &name);
+ free(name);
+ }
+
+ /* Paired */
+ boolean = device_is_paired(device);
+ dbus_message_iter_append_dict_entry(&dict, "Paired",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ /* Trusted */
+ boolean = read_trust(&src, device->address, GLOBAL_TRUST);
+ dbus_message_iter_append_dict_entry(&dict, "Trusted",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ /* Connected */
+ if (g_slist_find_custom(adapter->active_conn, &dst,
+ active_conn_find_by_bdaddr))
+ boolean = TRUE;
+ else
+ boolean = FALSE;
+
+ dbus_message_iter_append_dict_entry(&dict, "Connected",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ /* UUIDs */
+ uuids = g_new0(char *, g_slist_length(device->uuids) + 1);
+ for (i = 0, l = device->uuids; l; l = l->next, i++)
+ uuids[i] = l->data;
+ dbus_message_iter_append_dict_entry(&dict, "UUIDs",
+ DBUS_TYPE_ARRAY, &uuids);
+ g_free(uuids);
+
+ /* Adapter */
+ snprintf(path, sizeof(path), "/hci%d", adapter->dev_id);
+ ppath = path;
+ dbus_message_iter_append_dict_entry(&dict, "Adapter",
+ DBUS_TYPE_OBJECT_PATH, &ppath);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_alias(DBusConnection *conn, DBusMessage *msg,
+ const char *alias, void *data)
+{
+ struct device *device = data;
+ struct adapter *adapter = device->adapter;
+ bdaddr_t bdaddr;
+ int ecode;
+ char *str, filename[PATH_MAX + 1], path[MAX_PATH_LENGTH];
+
+ str2ba(device->address, &bdaddr);
+
+ /* Remove alias if empty string */
+ if (g_str_equal(alias, "")) {
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter->address,
+ "names");
+ str = textfile_caseget(filename, device->address);
+ ecode = remove_device_alias(adapter->dev_id, &bdaddr);
+ } else {
+ str = g_strdup(alias);
+ ecode = set_device_alias(adapter->dev_id, &bdaddr, alias);
+ }
+
+ if (ecode < 0)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ strerror(-ecode));
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, adapter->dev_id);
+
+ g_dbus_emit_signal(conn, path,
+ ADAPTER_INTERFACE, "RemoteAliasChanged",
+ DBUS_TYPE_STRING, &device->address,
+ DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_emit_property_changed(conn, dbus_message_get_path(msg),
+ DEVICE_INTERFACE, "Alias",
+ DBUS_TYPE_STRING, &str);
+
+ g_free(str);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_trust(DBusConnection *conn, DBusMessage *msg,
+ dbus_bool_t value, void *data)
+{
+ struct device *device = data;
+ struct adapter *adapter = device->adapter;
+ bdaddr_t local;
+ char path[MAX_PATH_LENGTH];
+
+ str2ba(adapter->address, &local);
+
+ write_trust(&local, device->address, GLOBAL_TRUST, value);
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, adapter->dev_id);
+
+ g_dbus_emit_signal(conn, path,
+ ADAPTER_INTERFACE,
+ value ? "TrustAdded" : "TrustRemoved",
+ DBUS_TYPE_STRING, &device->address,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_emit_property_changed(conn, dbus_message_get_path(msg),
+ DEVICE_INTERFACE, "Trusted",
+ DBUS_TYPE_BOOLEAN, &value);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter;
+ DBusMessageIter sub;
+ const char *property;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &property);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return invalid_args(msg);
+ dbus_message_iter_recurse(&iter, &sub);
+
+ 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);
+
+ return set_trust(conn, msg, value, data);
+ } else if (g_str_equal("Alias", property)) {
+ char *alias;
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
+ return invalid_args(msg);
+ dbus_message_iter_get_basic(&sub, &alias);
+
+ return set_alias(conn, msg, alias, data);
+ }
+
+ return invalid_args(msg);
+}
+
+static void discover_services_req_exit(void *user_data)
+{
+ struct device *device = user_data;
+ struct adapter *adapter = device->adapter;
+ bdaddr_t src, dst;
+
+ debug("DiscoverDevices requestor exited");
+
+ str2ba(adapter->address, &src);
+ str2ba(device->address, &dst);
+
+ bt_cancel_discovery(&src, &dst);
+}
+
+static DBusMessage *discover_services(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct device *device = user_data;
+ const char *pattern;
+ int err;
+
+ if (device->discov_active)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",
+ "Discover in progress");
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID) == FALSE)
+ goto fail;
+
+ if (strlen(pattern) == 0) {
+ err = device_browse(device, conn, msg, NULL);
+ if (err < 0)
+ goto fail;
+ } else {
+ uuid_t uuid;
+
+ if (bt_string2uuid(&uuid, pattern) < 0)
+ return invalid_args(msg);
+
+ err = device_browse(device, conn, msg, &uuid);
+ if (err < 0)
+ goto fail;
+ }
+
+ return NULL;
+
+fail:
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Discovery Failed");
+}
+
+static DBusMessage *cancel_discover(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct device *device = user_data;
+ struct adapter *adapter = device->adapter;
+ bdaddr_t src, dst;
+
+ if (!device->discov_active)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ "No pending discovery");
+
+ /* only the discover requestor can cancel the inquiry process */
+ if (!device->discov_requestor ||
+ strcmp(device->discov_requestor, dbus_message_get_sender(msg)))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotAuthorized",
+ "Not Authorized");
+
+ str2ba(adapter->address, &src);
+ str2ba(device->address, &dst);
+
+ if (bt_cancel_discovery(&src, &dst) < 0)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ "No pending discover");
+
+ return dbus_message_new_method_return(msg);
+}
+
+static gboolean disconnect_timeout(gpointer user_data)
+{
+ struct device *device = user_data;
+ struct active_conn_info *ci;
+ GSList *l;
+ disconnect_cp cp;
+ bdaddr_t bda;
+ int dd;
+
+ device->disconn_timer = 0;
+
+ str2ba(device->address, &bda);
+ l = g_slist_find_custom(device->adapter->active_conn,
+ &bda, active_conn_find_by_bdaddr);
+ if (!l)
+ return FALSE;
+
+ ci = l->data;
+ dd = hci_open_dev(device->adapter->dev_id);
+ if (dd < 0)
+ goto fail;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = htobs(ci->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 DBusMessage *disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct device *device = user_data;
+ GSList *l;
+ bdaddr_t bda;
+
+ str2ba(device->address, &bda);
+ l = g_slist_find_custom(device->adapter->active_conn,
+ &bda, active_conn_find_by_bdaddr);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotConnected",
+ "Device is not connected");
+
+ g_dbus_emit_signal(conn, device->path,
+ DEVICE_INTERFACE, "DisconnectRequested",
+ DBUS_TYPE_INVALID);
+
+ device->disconn_timer = g_timeout_add_seconds(DISCONNECT_TIMER,
+ disconnect_timeout, device);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property },
+ { "DiscoverServices", "s", "a{us}", discover_services,
+ G_DBUS_METHOD_FLAG_ASYNC},
+ { "CancelDiscovery", "", "", cancel_discover },
+ { "Disconnect", "", "", disconnect },
+ { }
+};
+
+static GDBusSignalTable device_signals[] = {
+ { "PropertyChanged", "sv" },
+ { "DisconnectRequested", "" },
+ { }
+};
+
+struct device *device_create(DBusConnection *conn, struct adapter *adapter,
+ const gchar *address)
+{
+ gchar *address_up;
+ struct device *device;
+
+ device = g_try_malloc0(sizeof(struct device));
+ if (device == NULL)
+ return NULL;
+
+ address_up = g_ascii_strup(address, -1);
+ device->path = g_strdup_printf("/hci%d/dev_%s",
+ adapter->dev_id, address_up);
+ g_strdelimit(device->path, ":", '_');
+ g_free(address_up);
+
+ debug("Creating device %s", device->path);
+
+ if (g_dbus_register_interface(conn, device->path, DEVICE_INTERFACE,
+ device_methods, device_signals, NULL,
+ device, device_free) == FALSE) {
+ device_free(device);
+ return NULL;
+ }
+
+ device->address = g_strdup(address);
+ device->adapter = adapter;
+
+ device->dev.path = device->path;
+ str2ba(device->address, &device->dev.dst);
+ str2ba(adapter->address, &device->dev.src);
+
+ return device;
+}
+
+void device_remove(DBusConnection *conn, struct device *device)
+{
+ GSList *list;
+ struct btd_device_driver *driver;
+ gchar *path = g_strdup(device->path);
+
+ debug("Removing device %s", path);
+
+ for (list = device->drivers; list; list = list->next) {
+ driver = (struct btd_device_driver *) list->data;
+
+ driver->remove(&device->dev);
+ }
+
+ g_dbus_unregister_interface(conn, path, DEVICE_INTERFACE);
+
+ g_free(path);
+}
+
+gint device_address_cmp(struct device *device, const gchar *address)
+{
+ return strcasecmp(device->address, address);
+}
+
+static int cmp_by_name(const void *data, const void *user_data)
+{
+ const struct btd_device_driver *dev_driver = data, *driver = user_data;
+
+ return (strcmp(dev_driver->name, driver->name));
+}
+
+void device_probe_drivers(struct device *device, GSList *uuids)
+{
+ GSList *list;
+ const char **uuid;
+ int err;
+
+ debug("Probe drivers for %s", device->path);
+
+ for (list = drivers; list; list = list->next) {
+ struct btd_device_driver *driver = list->data;
+ gboolean do_probe = FALSE;
+
+ for (uuid = driver->uuids; *uuid; uuid++) {
+ GSList *match = g_slist_find_custom(uuids, *uuid,
+ (GCompareFunc) strcasecmp);
+ if (match) {
+ do_probe = TRUE;
+ break;
+ }
+ }
+
+ if (do_probe == TRUE && !g_slist_find_custom(device->drivers,
+ driver, (GCompareFunc) cmp_by_name)) {
+
+ err = driver->probe(&device->dev);
+ if (err < 0) {
+ error("probe failed for driver %s",
+ driver->name);
+ continue;
+ }
+
+ device->drivers = g_slist_append(device->drivers,
+ driver);
+ }
+ }
+
+ for (list = uuids; list; list = list->next)
+ device->uuids = g_slist_insert_sorted(device->uuids,
+ list->data, (GCompareFunc) strcmp);
+}
+
+void device_remove_drivers(struct device *device, GSList *uuids)
+{
+ GSList *list;
+
+ debug("Remove drivers for %s", device->path);
+
+ for (list = device->drivers; list; list = list->next) {
+ struct btd_device_driver *driver = list->data;
+ const char **uuid;
+
+ for (uuid = driver->uuids; *uuid; uuid++) {
+ GSList *match = g_slist_find_custom(uuids, *uuid,
+ (GCompareFunc) strcasecmp);
+
+ if (!match)
+ continue;
+
+ driver->remove(&device->dev);
+ device->drivers = g_slist_remove(device->drivers,
+ driver);
+ }
+ }
+
+ for (list = uuids; list; list = list->next)
+ device->uuids = g_slist_remove(device->uuids, list->data);
+}
+
+static void iter_append_record(DBusMessageIter *dict, uint32_t handle,
+ const char *record)
+{
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_UINT32, &handle);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &record);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void discover_device_reply(struct browse_req *req, sdp_list_t *recs)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, dict;
+ sdp_list_t *seq;
+
+ reply = dbus_message_new_method_return(req->msg);
+ if (!reply)
+ return;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_STRING_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ for (seq = recs; seq; seq = seq->next) {
+ sdp_record_t *rec = (sdp_record_t *) seq->data;
+ sdp_buf_t result;
+
+ if (!rec)
+ break;
+
+ memset(&result, 0, sizeof(sdp_buf_t));
+
+ convert_sdp_record_to_xml(rec, &result,
+ append_and_grow_string);
+
+ if (result.data) {
+ const char *val = (char *) result.data;
+ iter_append_record(&dict, rec->handle, val);
+ free(result.data);
+ }
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ dbus_connection_send(req->conn, reply, NULL);
+ dbus_message_unref(reply);
+}
+
+static void services_changed(struct browse_req *req)
+{
+ struct device *device = req->device;
+ char **uuids;
+ GSList *l;
+ int i;
+
+ uuids = g_new0(char *, g_slist_length(device->uuids) + 1);
+ for (i = 0, l = device->uuids; l; l = l->next, i++)
+ uuids[i] = l->data;
+
+ dbus_connection_emit_property_changed(req->conn, device->path,
+ DEVICE_INTERFACE, "UUIDs",
+ DBUS_TYPE_ARRAY, &uuids);
+
+ g_free(uuids);
+}
+
+static void update_services(struct browse_req *req, sdp_list_t *recs)
+{
+ struct device *device = req->device;
+ sdp_list_t *seq;
+
+ for (seq = recs; seq; seq = seq->next) {
+ sdp_record_t *rec = (sdp_record_t *) seq->data;
+ sdp_list_t *svcclass = NULL;
+ gchar *uuid_str;
+ GSList *l;
+
+ if (!rec)
+ break;
+
+ if (sdp_get_service_classes(rec, &svcclass) < 0)
+ continue;
+
+ /* Extract the first element and skip the remainning */
+ uuid_str = bt_uuid2string(svcclass->data);
+ if (!uuid_str)
+ continue;
+
+ l = g_slist_find_custom(device->uuids, uuid_str,
+ (GCompareFunc) strcmp);
+ if (!l)
+ req->uuids_added = g_slist_append(req->uuids_added,
+ uuid_str);
+ else {
+ req->uuids_removed = g_slist_remove(req->uuids_removed,
+ l->data);
+ g_free(uuid_str);
+ }
+
+ sdp_list_free(svcclass, free);
+ }
+}
+
+static void store(struct device *device)
+{
+ struct adapter *adapter = device->adapter;
+ bdaddr_t src, dst;
+ char *str;
+
+ str2ba(adapter->address, &src);
+ str2ba(device->address, &dst);
+
+ if (!device->uuids) {
+ write_device_profiles(&src, &dst, "");
+ return;
+ }
+
+ str = bt_list2string(device->uuids);
+ write_device_profiles(&src, &dst, str);
+ g_free(str);
+}
+
+static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct browse_req *req = user_data;
+ struct device *device = req->device;
+ struct adapter *adapter = device->adapter;
+ bdaddr_t src, dst;
+ uuid_t uuid;
+ DBusMessage *reply;
+
+ if (err < 0)
+ goto proceed;
+
+ update_services(req, recs);
+
+ /* Public browsing successful or Single record requested */
+ if (req->browse == FALSE || (!req->search_uuid && recs))
+ goto probe;
+
+ if (uuid_list[++req->search_uuid]) {
+ sdp_uuid16_create(&uuid, uuid_list[req->search_uuid]);
+ str2ba(adapter->address, &src);
+ str2ba(device->address, &dst);
+ bt_search_service(&src, &dst, &uuid, browse_cb, user_data, NULL);
+ return;
+ }
+
+probe:
+
+ if (!req->uuids_added && !req->uuids_removed)
+ goto proceed;
+
+ /* Probe matching drivers for services added */
+ if (req->uuids_added)
+ device_probe_drivers(device, req->uuids_added);
+
+ /* Remove drivers for services removed */
+ if (req->uuids_removed)
+ device_remove_drivers(device, req->uuids_removed);
+
+ /* Store the device's profiles in the filesystem */
+ store(device);
+
+ /* Propagate services changes */
+ services_changed(req);
+
+proceed:
+ if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
+ "DiscoverServices")) {
+ discover_device_reply(req, recs);
+ goto cleanup;
+ }
+
+ g_dbus_emit_signal(req->conn, dbus_message_get_path(req->msg),
+ ADAPTER_INTERFACE, "DeviceCreated",
+ DBUS_TYPE_OBJECT_PATH, &device->path,
+ DBUS_TYPE_INVALID);
+
+ /* 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);
+
+ dbus_connection_send(req->conn, reply, NULL);
+ dbus_message_unref(reply);
+
+cleanup:
+ device->discov_active = 0;
+
+ if (device->discov_requestor) {
+ g_dbus_remove_watch(req->conn, device->discov_listener);
+ device->discov_listener = 0;
+ g_free(device->discov_requestor);
+ device->discov_requestor = NULL;
+ }
+
+ if (recs != NULL)
+ sdp_list_free(recs, (sdp_free_func_t) sdp_record_free);
+
+ dbus_message_unref(req->msg);
+ dbus_connection_unref(req->conn);
+ g_slist_free(req->uuids_added);
+ g_slist_free(req->uuids_removed);
+ g_free(req);
+}
+
+int device_browse(struct device *device, DBusConnection *conn,
+ DBusMessage *msg, uuid_t *search)
+{
+ struct adapter *adapter = device->adapter;
+ struct browse_req *req;
+ bdaddr_t src, dst;
+ uuid_t uuid;
+ GSList *l;
+
+ req = g_new0(struct browse_req, 1);
+ req->conn = dbus_connection_ref(conn);
+ req->msg = dbus_message_ref(msg);
+ req->device = device;
+
+ for (l = device->uuids; l; l = l->next)
+ req->uuids_removed = g_slist_append(req->uuids_removed,
+ l->data);
+
+ str2ba(adapter->address, &src);
+ str2ba(device->address, &dst);
+
+ if (search) {
+ memcpy(&uuid, search, sizeof(uuid_t));
+ req->browse = FALSE;
+ } else {
+ sdp_uuid16_create(&uuid, uuid_list[req->search_uuid]);
+ req->browse = TRUE;
+ }
+
+ device->discov_active = 1;
+ device->discov_requestor = g_strdup(dbus_message_get_sender(msg));
+ /* Track the request owner to cancel it
+ * automatically if the owner exits */
+ device->discov_listener = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ discover_services_req_exit,
+ device, NULL);
+
+ return bt_search_service(&src, &dst, &uuid, browse_cb, req, NULL);
+}
+
+int btd_register_device_driver(struct btd_device_driver *driver)
+{
+ const char **uuid;
+
+ drivers = g_slist_append(drivers, driver);
+
+ for (uuid = driver->uuids; *uuid; uuid++) {
+ debug("name %s uuid %s", driver->name, *uuid);
+ }
+
+ register_service(driver->name, driver->uuids);
+
+ return 0;
+}
+
+void btd_unregister_device_driver(struct btd_device_driver *driver)
+{
+ unregister_service(driver->name);
+
+ drivers = g_slist_remove(drivers, driver);
+}
diff --git a/utils/hcid/device.h b/utils/hcid/device.h
new file mode 100644
index 00000000..e5a322b3
--- /dev/null
+++ b/utils/hcid/device.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define DEVICE_INTERFACE "org.bluez.Device"
+
+struct btd_device {
+ char *path;
+ bdaddr_t src;
+ bdaddr_t dst;
+};
+
+struct device {
+ struct btd_device dev;
+ gchar *address;
+ gchar *path;
+ struct adapter *adapter;
+ GSList *uuids;
+ GSList *drivers;
+ gboolean temporary;
+ struct agent *agent;
+ guint disconn_timer;
+ int discov_active; /* Service discovery active */
+ char *discov_requestor; /* discovery requestor unique name */
+ guint discov_listener;
+
+ /* For Secure Simple Pairing */
+ uint8_t cap;
+ uint8_t auth;
+};
+
+struct device *device_create(DBusConnection *conn, struct adapter *adapter,
+ const gchar *address);
+void device_remove(DBusConnection *conn, struct device *device);
+gint device_address_cmp(struct device *device, const gchar *address);
+int device_browse(struct device *device, DBusConnection *conn,
+ DBusMessage *msg, uuid_t *search);
+void device_probe_drivers(struct device *device, GSList *uuids);
+
+#define BTD_UUIDS(args...) ((const char *[]) { args, NULL } )
+
+struct btd_device_driver {
+ const char *name;
+ const char **uuids;
+ int (*probe) (struct btd_device *device);
+ void (*remove) (struct btd_device *device);
+};
+
+int btd_register_device_driver(struct btd_device_driver *driver);
+void btd_unregister_device_driver(struct btd_device_driver *driver);
diff --git a/utils/hcid/hcid.8 b/utils/hcid/hcid.8
new file mode 100644
index 00000000..a7ab0410
--- /dev/null
+++ b/utils/hcid/hcid.8
@@ -0,0 +1,101 @@
+.\"
+.TH "HCID" "8" "March 2004" "hcid - HCI daemon" "System management commands"
+.SH "NAME"
+hcid \- Bluetooth Host Controller Interface Daemon
+
+.SH "SYNOPSIS"
+.B hcid
+[
+.B \-n
+] [
+.B \-f
+.I config\-file
+]
+
+.SH "DESCRIPTION"
+This manual page documents briefly the
+.B hcid
+daemon, which manages all the Bluetooth devices.
+.B hcid
+itself does not accept many command\-line options, as most of its
+configuration is done in the
+.B hcid.conf
+file, which has its own man page.
+.B hcid
+can also provide a number of services via the D-BUS message bus
+system.
+.SH "OPTIONS"
+.TP
+.BI \-n
+Don't fork to run daemon in background.
+.TP
+.BI \-d
+Enable debug information output.
+.TP
+.BI \-s
+Enable internal SDP server.
+.TP
+.BI \-m\ mtu\-size
+Use specific MTU size for SDP server.
+.TP
+.BI \-f\ config\-file
+Use alternate configuration file instead of /etc/bluetooth/hcid.conf
+.SH "FILES"
+.TP
+.I /etc/bluetooth/hcid.conf
+Default location of the global configuration file.
+
+.TP
+.I /var/lib/bluetooth/nn:nn:nn:nn:nn:nn/linkkeys
+Default location for link keys of paired devices. The directory
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
+is the address of the local device. The file is line separated, with
+the following columns separated by whitespace:
+
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
+
+\fInnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\fP Link key.
+
+\fIn\fP Link type integer.
+
+.TP
+.I /var/lib/bluetooth/nn:nn:nn:nn:nn:nn/names
+Default location for the device name cache. The directory
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
+is the address of the local device. The file is line separated, with
+the following columns separated by whitespace:
+
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
+
+\fIname\fP Remote device name, terminated with newline.
+
+.TP
+.I /var/lib/bluetooth/nn:nn:nn:nn:nn:nn/features
+Default location for the features cache. The directory
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
+is the address of the local device. The file is line separated, with
+the following columns separated by whitespace:
+
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
+
+\fInnnnnnnnnnnnnnnn\fP Remote device LMP features coded as an 8 byte bitfield.
+
+.TP
+.I /var/lib/bluetooth/nn:nn:nn:nn:nn:nn/manufacturers
+Default location for the manufacturers cache. The directory
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
+is the address of the local device. The file is line separated, with
+the following columns separated by whitespace:
+
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
+
+\fIn\fP Remote device manufacturer integer.
+
+\fIn\fP Remote device LMP version integer.
+
+\fIn\fP Remote device LMP sub-version integer.
+
+.SH "SEE ALSO"
+\fBhcid.conf\fR(5)
+.SH "AUTHOR"
+This manual page was written by Philipp Matthias Hahn and Fredrik Noring.
diff --git a/utils/hcid/hcid.conf b/utils/hcid/hcid.conf
new file mode 100644
index 00000000..b6ce3b48
--- /dev/null
+++ b/utils/hcid/hcid.conf
@@ -0,0 +1,57 @@
+#
+# HCI daemon configuration file.
+#
+
+# HCId options
+options {
+ # Automatically initialize new devices
+ autoinit yes;
+
+ # Security Manager mode
+ # none - Security manager disabled
+ # auto - Use local PIN for incoming connections
+ # user - Always ask user for a PIN
+ #
+ security user;
+
+ # Pairing mode
+ # none - Pairing disabled
+ # multi - Allow pairing with already paired devices
+ # once - Pair once and deny successive attempts
+ pairing multi;
+
+ # Default PIN code for incoming connections
+ passkey "BlueZ";
+}
+
+# Default settings for HCI devices
+device {
+ # Local device name
+ # %d - device id
+ # %h - host name
+ name "BlueZ (%d)";
+
+ # Local device class
+ class 0x000100;
+
+ # Default packet type
+ #pkt_type DH1,DM1,HV1;
+
+ # Inquiry and Page scan
+ iscan enable; pscan enable;
+
+ # Default link mode
+ # none - no specific policy
+ # accept - always accept incoming connections
+ # master - become master on incoming connections,
+ # deny role switch on outgoing connections
+ lm accept;
+
+ # Default link policy
+ # none - no specific policy
+ # rswitch - allow role switch
+ # hold - allow hold mode
+ # sniff - allow sniff mode
+ # park - allow park mode
+ lp rswitch,hold,sniff,park;
+}
diff --git a/utils/hcid/hcid.conf.5 b/utils/hcid/hcid.conf.5
new file mode 100644
index 00000000..cb5bcfa9
--- /dev/null
+++ b/utils/hcid/hcid.conf.5
@@ -0,0 +1,227 @@
+.TH "HCID.CONF" "5" "March 2004" "hcid.conf - HCI daemon" "System management commands"
+.SH "NAME"
+/etc/bluetooth/hcid.conf \- Configuration file for the hcid Bluetooth HCI daemon
+
+.SH "DESCRIPTION"
+/etc/bluetooth/hcid.conf contains all the options needed by the Bluetooth Host Controller Interface daemon.
+
+It consists of sections and parameters. A section begins with
+the name of the section followed by optional specifiers and the
+parameters inside curly brackets. Sections contain parameters of
+the form:
+.TP
+\fIname\fP \fIvalue1\fP, \fIvalue2\fP ... ;
+
+.PP
+Any character after a hash ('#') character is ignored until newline.
+Whitespace is also ignored.
+
+
+The valid section names for
+.B hcid.conf
+are, at the moment:
+
+.TP
+.B options
+contains generic options for hcid and the pairing policy.
+.TP
+.B device
+contains lower\-level options for the hci devices connected to the computer.
+.SH "OPTIONS SECTION"
+The following parameters may be present in an option section:
+
+
+.TP
+\fBautoinit\fP yes|no
+
+Automatically initialize newly connected devices. The default is \fIno\fP.
+
+
+.TP
+\fBpairing\fP none|multi|once
+
+\fInone\fP means that pairing is disabled. \fImulti\fP allows pairing
+with already paired devices. \fIonce\fP allows pairing once and denies
+successive attempts. The default hcid configuration is shipped with \fBmulti\fP
+enabled
+
+.TP
+\fBoffmode\fP noscan|devdown
+
+\fInoscan\fP means that page and inquiry scans are disabled when you call
+SetMode("off"). \fIdevdown\fP sets the adapter into down state (same what
+\fIhciconfig hci0 down\fP does).
+
+.TP
+\fBdeviceid\fP <vendor>:<product>:<version>
+
+This option allows to specify the vendor and product information of the
+Bluetooth device ID service record.
+
+.TP
+\fBpasskey\fP "\fIpin\fP"
+
+The default PIN for incoming connections if \fBsecurity\fP has been
+set to \fIauto\fP.
+
+.TP
+\fBsecurity\fP none|auto|user
+
+\fInone\fP means the security manager is disabled. \fIauto\fP uses
+local PIN, by default from pin_code, for incoming
+connections. \fIuser\fP always asks the user for a PIN.
+
+.SH "DEVICE SECTION"
+Parameters within a device section with no specifier, the default
+device section, will be applied to all devices and device sections
+where these are unspecified. The following optional device specifiers
+are supported:
+
+.TP
+\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
+
+Parameters specified within this section will be applied to the device
+with this \fIdevice bluetooth address\fP. All other parameters are applied from
+the default section.
+
+.TP
+\fBhci\fIn\fP
+
+Parameters specified within this section will be applied to the device
+with this \fIdevice interface\fP, unless that device is matched by a
+\fIdevice address\fP section. All other parameters are applied from
+the default section.
+
+
+.PP
+\fBNote\fP: Most of the options supported in the \fBdevice\fP section are described to some extent in the bluetooth specification version 1.2 Vol2, Part E section 6. Please refer to it for technical details.
+
+.PP
+The following parameters may be present in a device section:
+
+.TP
+\fBname\fP "\fIname\fP"
+
+The device name. \fI%d\fP inserts the device id. \fI%h\fP inserts
+the host name.
+
+
+.TP
+\fBclass\fP 0x\fISSDDdd\fP (three bytes)
+
+The Bluetooth Device Class is described in the Bluetooth Specification section 1.2 ("Assigned Numbers \- Bluetooth Baseband").
+
+The default shipped with hcid is 0x000100 which simply stands for "Computer".
+
+The Bluetooth device class is a high\-level description of the bluetooth device, composed of three bytes: the "Major Service Class" (byte "SS" above), the "Major Device Class" (byte "DD" above) and the "Minor Device Class" (byte "dd" above). These classes describe the high\-level capabilities of the device, such as "Networking Device", "Computer", etc. This information is often used by clients who are looking for a certain type of service around them.
+
+Where it becomes tricky is that another type of mechanism for service discovery exists: "SDP", as in "Service Discovery Protocol".
+
+In practice, most Bluetooth clients scan their surroundings in two successive steps: they first look for all bluetooth devices around them and find out their "class". You can do this on Linux with the \fBhcitool scan\fP command. Then, they use SDP in order to check if a device in a given class offers the type of service that they want.
+
+This means that the hcid.conf "class" parameter needs to be set up properly if particular services are running on the host, such as "PAN", or "OBEX Obect Push", etc: in general a device looking for a service such as "Network Access Point" will only scan for this service on devices containing "Networking" in their major service class.
+
+
+.IP
+Major service class byte allocation (from LSB to MSB):
+
+Bit 1: Positioning (Location identification)
+
+Bit 2: Networking (LAN, Ad hoc, ...)
+
+Bit 3: Rendering (Printing, Speaker, ...)
+
+Bit 4: Capturing (Scanner, Microphone, ...)
+
+Bit 5: Object Transfer (v\-Inbox, v\-Folder, ...)
+
+Bit 6: Audio (Speaker, Microphone, Headset service, ...)
+
+Bit 7: Telephony (Cordless telephony, Modem, Headset service, ...)
+
+Bit 8: Information (WEB\-server, WAP\-server, ...)
+
+.IP
+Example: class 0x02hhhh : the device offers networking service
+
+
+.IP
+Major device class allocation:
+
+0x00: Miscellaneous
+
+0x01: Computer (desktop,notebook, PDA, organizers, .... )
+
+0x02: Phone (cellular, cordless, payphone, modem, ...)
+
+0x03: LAN /Network Access point
+
+0x04: Audio/Video (headset,speaker,stereo, video display, vcr.....
+
+0x05: Peripheral (mouse, joystick, keyboards, ..... )
+
+0x06: Imaging (printing, scanner, camera, display, ...)
+
+Other values are not defined (refer to the Bluetooth specification for more details
+
+.IP
+Minor device class allocation: the meaning of this byte depends on the major class allocation, please refer to the Bluetooth specifications for more details).
+
+.IP
+.B Example:
+if PAND runs on your server, you need to set up at least \fBclass 0x020100\fP, which stands for "Service Class: Networking" and "Device Class: Computer, Uncategorized".
+
+
+.TP
+\fBiscan\fP enable|disable
+.TP
+\fBpscan\fP enable|disable
+
+Bluetooth devices discover and connect to each other through the use of two special Bluetooth channels, the Inquiry and Page channels (described in the Bluetooth Spec Volume 1, Part A, Section 3.3.3, page 35). These two options enable the channels on the bluetooth device.
+
+\fBiscan enable\fP: makes the bluetooth device "discoverable" by enabling it to answer "inquiries" from other nearby bluetooth devices.
+
+\fBpscan enable\fP: makes the bluetooth device "connectable to" by enabling the use of the "page scan" channel.
+
+.TP
+\fBlm\fP none|accept,master
+
+\fInone\fP means no specific policy. \fIaccept\fP means always accept
+incoming connections. \fImaster\fP means become master on incoming
+connections and deny role switch on outgoing connections.
+
+.TP
+\fBlp\fP none|rswitch,hold,sniff,park
+
+\fInone\fP means no specific policy. \fIrswitch\fP means allow role
+switch. \fIhold\fP means allow hold mode. \fIsniff\fP means allow
+sniff mode. \fIpark\fP means allow park mode. Several options can be
+combined.
+
+This option determines the various operational modes that are allowed for this device when it participates to a piconet. Normally hold and sniff should be enabled for standard operations.
+
+hold: this mode is related to synchronous communications (SCO voice channel for example).
+
+sniff: when in this mode, a device is only present on the piconet during determined slots of time, allowing it to do other things when it is "absent", for example to scan for other bluetooth devices.
+
+park: this is a mode where the device is put on standby on the piconet, for power\-saving purposes for example.
+
+rswitch: this is a mode that enables role\-switch (master <\-> slave) between two devices in a piconet. It is not clear whether this needs to be enabled in order to make the "lm master" setting work properly or not.
+
+.TP
+\fBpageto\fP \fIn\fP
+
+Page Timeout measured in number of baseband slots. Interval length = N * 0.625 msec (1 baseband slot)
+
+.TP
+\fBdiscovto\fP \fIn\fP
+
+The time in seconds that the device will stay in discoverable mode. 0 disables this feature and forces the device to be always discoverable.
+
+.SH "FILES"
+.TP
+.I /etc/bluetooth/hcid.conf
+Default location of the global configuration file.
+
+.SH "AUTHOR"
+This manual page was written by Edouard Lafargue, Fredrik Noring, Maxim Krasnyansky and Marcel Holtmann.
diff --git a/utils/hcid/hcid.h b/utils/hcid/hcid.h
new file mode 100644
index 00000000..8a4c0f48
--- /dev/null
+++ b/utils/hcid/hcid.h
@@ -0,0 +1,218 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <time.h>
+#include <sys/types.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "logging.h"
+
+#define HCID_CONFIG_FILE CONFIGDIR "/hcid.conf"
+
+#define HCID_DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
+
+/* When all services should trust a remote device */
+#define GLOBAL_TRUST "[all]"
+
+enum {
+ HCID_SET_NAME,
+ HCID_SET_CLASS,
+ HCID_SET_VOICE,
+ HCID_SET_INQMODE,
+ HCID_SET_PAGETO,
+ HCID_SET_DISCOVTO,
+ HCID_SET_PTYPE,
+ HCID_SET_LM,
+ HCID_SET_LP,
+};
+
+/*
+ * Scanning modes, used by DEV_SET_MODE
+ * off: remote devices are not allowed to find or connect to this device
+ * connectable: remote devices are allowed to connect, but they are not
+ * allowed to find it.
+ * discoverable: remote devices are allowed to connect and find this device
+ * limited: limited discoverable - GIAC + IAC enabled and set limited
+ * bit on device class.
+ */
+
+#define MODE_OFF 0x00
+#define MODE_CONNECTABLE 0x01
+#define MODE_DISCOVERABLE 0x02
+#define MODE_LIMITED 0x03
+#define MODE_UNKNOWN 0xff
+
+struct device_opts {
+ unsigned long flags;
+ char *name;
+ uint32_t class;
+ uint16_t voice;
+ uint8_t inqmode;
+ uint16_t pageto;
+ uint16_t pkt_type;
+ uint16_t link_mode;
+ uint16_t link_policy;
+ uint8_t scan;
+ uint8_t mode;
+ uint32_t discovto;
+};
+
+extern struct device_opts default_device;
+extern struct device_opts *parser_device;
+
+struct device_list {
+ char *ref; /* HCI device or Bluetooth address */
+ struct device_list *next;
+ struct device_opts opts;
+};
+
+struct hcid_opts {
+ char host_name[40];
+ int auto_init;
+ int security;
+ int pairing;
+ int offmode;
+ char deviceid[15];
+
+ char *config_file;
+
+ uint8_t pin_code[16];
+ int pin_len;
+
+ int sock;
+};
+extern struct hcid_opts hcid;
+
+typedef enum {
+ REQ_PENDING,
+ REQ_SENT
+} req_status_t;
+
+struct hci_req_data {
+ int dev_id;
+ int event;
+ req_status_t status;
+ bdaddr_t dba;
+ uint16_t ogf;
+ uint16_t ocf;
+ void *cparam;
+ int clen;
+};
+
+struct hci_req_data *hci_req_data_new(int dev_id, const bdaddr_t *dba, uint16_t ogf, uint16_t ocf, int event, const void *cparam, int clen);
+void hci_req_queue_append(struct hci_req_data *data);
+void hci_req_queue_remove(int dev_id, bdaddr_t *dba);
+
+#define HCID_SEC_NONE 0
+#define HCID_SEC_AUTO 1
+#define HCID_SEC_USER 2
+
+#define HCID_PAIRING_NONE 0
+#define HCID_PAIRING_MULTI 1
+#define HCID_PAIRING_ONCE 2
+
+#define HCID_OFFMODE_DEVDOWN 0
+#define HCID_OFFMODE_NOSCAN 1
+
+int read_config(char *file);
+
+struct device_opts *alloc_device_opts(char *ref);
+
+uint8_t get_startup_scan(int hdev);
+uint8_t get_startup_mode(int hdev);
+int get_discoverable_timeout(int dev_id);
+
+void init_security_data(void);
+void start_security_manager(int hdev);
+void stop_security_manager(int hdev);
+void toggle_pairing(int enable);
+
+void set_pin_length(bdaddr_t *sba, int length);
+
+void init_adapters(void);
+int add_adapter(uint16_t dev_id);
+int remove_adapter(uint16_t dev_id);
+int start_adapter(uint16_t dev_id);
+int stop_adapter(uint16_t dev_id);
+int update_adapter(uint16_t dev_id);
+
+int get_device_address(uint16_t dev_id, char *address, size_t size);
+int get_device_class(uint16_t dev_id, uint8_t *class);
+int set_device_class(uint16_t dev_id, uint8_t *class);
+int get_device_version(uint16_t dev_id, char *version, size_t size);
+int get_device_revision(uint16_t dev_id, char *revision, size_t size);
+int get_device_manufacturer(uint16_t dev_id, char *manufacturer, size_t size);
+int get_device_company(uint16_t dev_id, char *company, size_t size);
+
+int set_simple_pairing_mode(uint16_t dev_id, uint8_t mode);
+int get_device_name(uint16_t dev_id, char *name, size_t size);
+int set_device_name(uint16_t dev_id, const char *name);
+int get_device_alias(uint16_t dev_id, const bdaddr_t *bdaddr, char *alias, size_t size);
+int set_device_alias(uint16_t dev_id, const bdaddr_t *bdaddr, const char *alias);
+
+int get_encryption_key_size(uint16_t dev_id, const bdaddr_t *baddr);
+
+int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout);
+int read_discoverable_timeout(bdaddr_t *bdaddr, int *timeout);
+int write_device_mode(bdaddr_t *bdaddr, const char *mode);
+int read_device_mode(bdaddr_t *bdaddr, char *mode, int length);
+int read_on_mode(bdaddr_t *bdaddr, char *mode, int length);
+int write_local_name(bdaddr_t *bdaddr, char *name);
+int read_local_name(bdaddr_t *bdaddr, char *name);
+int write_local_class(bdaddr_t *bdaddr, uint8_t *class);
+int read_local_class(bdaddr_t *bdaddr, uint8_t *class);
+int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class);
+int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class);
+int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name);
+int read_device_name(bdaddr_t *local, bdaddr_t *peer, char *name);
+int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data);
+int write_l2cap_info(bdaddr_t *local, bdaddr_t *peer,
+ uint16_t mtu_result, uint16_t mtu,
+ uint16_t mask_result, uint32_t mask);
+int read_l2cap_info(bdaddr_t *local, bdaddr_t *peer,
+ 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_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
+int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
+int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length);
+int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type);
+int read_pin_length(bdaddr_t *local, bdaddr_t *peer);
+int read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin);
+gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service);
+int write_trust(bdaddr_t *local, const char *addr, const char *service, gboolean trust);
+GSList *list_trusts(bdaddr_t *local, const char *service);
+int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles);
+int delete_entry(bdaddr_t *src, const char *storage, const char *key);
+
+gboolean plugin_init(GKeyFile *config);
+void plugin_cleanup(void);
+void __probe_servers(const char *adapter);
+void __remove_servers(const char *adapter);
diff --git a/utils/hcid/kword.c b/utils/hcid/kword.c
new file mode 100644
index 00000000..3a89e5a3
--- /dev/null
+++ b/utils/hcid/kword.c
@@ -0,0 +1,102 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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 <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hcid.h"
+#include "kword.h"
+#include "parser.h"
+
+struct kword cfg_keyword[] = {
+ { "options", K_OPTIONS },
+ { "default", K_DEVICE },
+ { "device", K_DEVICE },
+ { "autoinit", K_AUTOINIT },
+ { "security", K_SECURITY },
+ { "pairing", K_PAIRING },
+ { "offmode", K_OFFMODE },
+ { "deviceid", K_DEVICEID },
+ { "pkt_type", K_PTYPE },
+ { "lm", K_LM },
+ { "lp", K_LP },
+ { "iscan", K_ISCAN },
+ { "pscan", K_PSCAN },
+ { "name", K_NAME },
+ { "class", K_CLASS },
+ { "voice", K_VOICE },
+ { "pageto", K_PAGETO },
+ { "discovto", K_DISCOVTO },
+ { "passkey", K_PASSKEY },
+
+ { "yes", K_YES },
+ { "no", K_NO },
+ { "enable", K_YES },
+ { "disable", K_NO },
+ { NULL , 0 }
+};
+
+struct kword sec_param[] = {
+ { "none", HCID_SEC_NONE },
+ { "auto", HCID_SEC_AUTO },
+ { "user", HCID_SEC_USER },
+ { NULL , 0 }
+};
+
+struct kword pair_param[] = {
+ { "none", HCID_PAIRING_NONE },
+ { "multi", HCID_PAIRING_MULTI },
+ { "once", HCID_PAIRING_ONCE },
+ { NULL , 0 }
+};
+
+struct kword off_param[] = {
+ { "devdown", HCID_OFFMODE_DEVDOWN },
+ { "noscan", HCID_OFFMODE_NOSCAN },
+ { NULL , 0 }
+};
+
+int lineno;
+
+int find_keyword(struct kword *kw, char *str)
+{
+ while (kw->str) {
+ if (!strcmp(str,kw->str))
+ return kw->type;
+ kw++;
+ }
+ return -1;
+}
diff --git a/utils/hcid/kword.h b/utils/hcid/kword.h
new file mode 100644
index 00000000..ac4781cc
--- /dev/null
+++ b/utils/hcid/kword.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct kword {
+ char *str;
+ int type;
+};
+extern int lineno;
+
+extern struct kword cfg_keyword[];
+extern struct kword sec_param[];
+extern struct kword pair_param[];
+extern struct kword off_param[];
+
+int find_keyword(struct kword *kw, char *str);
diff --git a/utils/hcid/lexer.c b/utils/hcid/lexer.c
new file mode 100644
index 00000000..7cb709bf
--- /dev/null
+++ b/utils/hcid/lexer.c
@@ -0,0 +1,1946 @@
+
+#line 3 "lexer.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 15
+#define YY_END_OF_BUFFER 16
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[70] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 16, 14, 1, 3,
+ 9, 14, 9, 8, 14, 7, 7, 8, 8, 15,
+ 9, 11, 0, 10, 0, 2, 9, 11, 8, 12,
+ 7, 8, 8, 8, 11, 11, 0, 7, 0, 8,
+ 6, 8, 7, 8, 0, 6, 4, 7, 0, 0,
+ 6, 4, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 0, 0, 0, 0, 0, 0, 5, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 4, 4, 4, 1, 1,
+ 1, 4, 4, 7, 8, 9, 10, 11, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 13, 1, 1,
+ 4, 1, 1, 4, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 1, 4, 1, 4, 8, 1, 14, 14, 15, 14,
+
+ 14, 14, 14, 16, 17, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 18,
+ 14, 14, 1, 1, 1, 4, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[19] =
+ { 0,
+ 1, 1, 2, 3, 1, 3, 3, 4, 4, 1,
+ 5, 5, 1, 5, 5, 5, 5, 5
+ } ;
+
+static yyconst flex_int16_t yy_base[93] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 140, 227, 227, 227,
+ 131, 132, 18, 28, 0, 34, 117, 42, 118, 227,
+ 121, 120, 121, 120, 111, 227, 60, 73, 83, 99,
+ 89, 15, 104, 112, 92, 129, 0, 139, 0, 18,
+ 154, 44, 162, 81, 0, 172, 46, 78, 0, 75,
+ 72, 57, 0, 0, 0, 0, 0, 71, 227, 0,
+ 0, 69, 0, 0, 68, 0, 0, 227, 227, 190,
+ 193, 198, 203, 206, 208, 211, 216, 221, 74, 72,
+ 67, 66, 61, 59, 54, 42, 39, 34, 31, 28,
+ 19, 17
+
+ } ;
+
+static yyconst flex_int16_t yy_def[93] =
+ { 0,
+ 69, 1, 70, 70, 70, 70, 69, 69, 69, 69,
+ 71, 72, 73, 74, 75, 69, 16, 16, 18, 69,
+ 71, 76, 72, 72, 77, 69, 73, 78, 74, 75,
+ 69, 31, 69, 31, 76, 78, 75, 69, 79, 38,
+ 69, 38, 29, 29, 80, 69, 43, 43, 81, 69,
+ 46, 29, 82, 83, 84, 85, 86, 69, 69, 87,
+ 88, 69, 89, 90, 69, 91, 92, 69, 0, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69
+
+ } ;
+
+static yyconst flex_int16_t yy_nxt[246] =
+ { 0,
+ 8, 9, 10, 11, 12, 13, 8, 14, 11, 15,
+ 16, 17, 8, 18, 18, 19, 18, 18, 25, 25,
+ 26, 68, 25, 67, 28, 40, 40, 25, 44, 44,
+ 25, 21, 65, 21, 22, 64, 21, 21, 62, 21,
+ 22, 29, 21, 61, 31, 31, 59, 32, 32, 32,
+ 32, 33, 32, 32, 47, 47, 52, 52, 58, 32,
+ 25, 25, 26, 57, 25, 56, 28, 52, 52, 25,
+ 55, 53, 25, 25, 25, 26, 50, 25, 45, 28,
+ 66, 63, 25, 60, 69, 25, 21, 54, 21, 22,
+ 69, 21, 21, 49, 21, 22, 29, 21, 22, 38,
+
+ 38, 39, 40, 40, 40, 40, 40, 21, 37, 21,
+ 22, 29, 21, 26, 41, 41, 39, 41, 41, 41,
+ 41, 41, 40, 40, 24, 24, 22, 22, 42, 25,
+ 25, 26, 34, 25, 32, 28, 24, 22, 25, 69,
+ 69, 25, 21, 69, 21, 22, 29, 21, 69, 43,
+ 43, 69, 44, 44, 44, 44, 44, 21, 69, 21,
+ 22, 29, 21, 69, 46, 46, 69, 46, 46, 46,
+ 46, 46, 48, 48, 49, 21, 69, 21, 22, 29,
+ 21, 69, 51, 51, 49, 51, 51, 51, 51, 51,
+ 20, 20, 20, 20, 20, 21, 21, 21, 23, 69,
+
+ 23, 23, 23, 27, 27, 27, 27, 27, 29, 29,
+ 29, 30, 30, 35, 35, 35, 25, 25, 25, 25,
+ 25, 36, 36, 36, 36, 36, 7, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69
+ } ;
+
+static yyconst flex_int16_t yy_chk[246] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 13, 13,
+ 13, 92, 13, 91, 13, 32, 32, 13, 40, 40,
+ 13, 14, 90, 14, 14, 89, 14, 16, 88, 16,
+ 16, 16, 16, 87, 16, 16, 86, 16, 16, 16,
+ 16, 16, 18, 18, 42, 42, 47, 47, 85, 18,
+ 27, 27, 27, 84, 27, 83, 27, 52, 52, 27,
+ 82, 81, 27, 28, 28, 28, 80, 28, 79, 28,
+ 65, 62, 28, 58, 51, 28, 29, 50, 29, 29,
+ 48, 29, 31, 44, 31, 31, 31, 31, 35, 31,
+
+ 31, 31, 31, 31, 31, 31, 31, 33, 30, 33,
+ 33, 33, 33, 25, 33, 33, 33, 33, 33, 33,
+ 33, 33, 34, 34, 24, 23, 22, 21, 34, 36,
+ 36, 36, 19, 36, 17, 36, 12, 11, 36, 7,
+ 0, 36, 38, 0, 38, 38, 38, 38, 0, 38,
+ 38, 0, 38, 38, 38, 38, 38, 41, 0, 41,
+ 41, 41, 41, 0, 41, 41, 0, 41, 41, 41,
+ 41, 41, 43, 43, 43, 46, 0, 46, 46, 46,
+ 46, 0, 46, 46, 46, 46, 46, 46, 46, 46,
+ 70, 70, 70, 70, 70, 71, 71, 71, 72, 0,
+
+ 72, 72, 72, 73, 73, 73, 73, 73, 74, 74,
+ 74, 75, 75, 76, 76, 76, 77, 77, 77, 77,
+ 77, 78, 78, 78, 78, 78, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lexer.l"
+#line 2 "lexer.l"
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hcid.h"
+#include "kword.h"
+#include "parser.h"
+
+static char str_buf[255];
+
+#define ECHO {;}
+#define YY_DECL int yylex(void)
+
+int cfg_error(const char *ftm, ...);
+int yyerror(char *str);
+
+
+#line 580 "lexer.c"
+
+#define INITIAL 0
+#define OPTION 1
+#define PARAM 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in (void );
+
+void yyset_in (FILE * in_str );
+
+FILE *yyget_out (void );
+
+void yyset_out (FILE * out_str );
+
+int yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ unsigned n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 74 "lexer.l"
+
+#line 764 "lexer.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 70 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 227 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 75 "lexer.l"
+{
+ /* Skip spaces and tabs */
+ ;
+}
+ YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 80 "lexer.l"
+{
+ /* Skip comments */
+ lineno++;
+}
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 85 "lexer.l"
+{
+ lineno++;
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 89 "lexer.l"
+{
+ yylval.str = yytext;
+ return HCI;
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 94 "lexer.l"
+{
+ yylval.str = yytext;
+ return BDADDR;
+}
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 99 "lexer.l"
+{
+ yylval.num = strtol(yytext, NULL, 16);
+ return NUM;
+}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 104 "lexer.l"
+{
+ yylval.num = atoi(yytext);
+ return NUM;
+}
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 109 "lexer.l"
+{
+ int kw = find_keyword(cfg_keyword, yytext);
+ if( kw != -1 )
+ return kw;
+
+ yylval.str = yytext;
+ return WORD;
+}
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 118 "lexer.l"
+{
+ yylval.str = yytext;
+ return WORD;
+}
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 123 "lexer.l"
+{
+ if (yyleng > sizeof(str_buf) - 1) {
+ yyerror("string too long");
+ return 0;
+ }
+
+ strncpy(str_buf, yytext + 1, yyleng - 2);
+ str_buf[yyleng - 2] = '\0';
+
+ yylval.str = str_buf;
+ return STRING;
+}
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 136 "lexer.l"
+{
+ yylval.str = yytext;
+ return LIST;
+}
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 141 "lexer.l"
+{
+ yylval.str = yytext;
+ return PATH;
+}
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 146 "lexer.l"
+{
+ yylval.str = yytext;
+ return ID;
+}
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 151 "lexer.l"
+{
+ return *yytext;
+}
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 155 "lexer.l"
+ECHO;
+ YY_BREAK
+#line 976 "lexer.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(OPTION):
+case YY_STATE_EOF(PARAM):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 70 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 70 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 69);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 155 "lexer.l"
+
+
+
+int yywrap(void)
+{
+ return 1;
+}
+
diff --git a/utils/hcid/lexer.l b/utils/hcid/lexer.l
new file mode 100644
index 00000000..768a0783
--- /dev/null
+++ b/utils/hcid/lexer.l
@@ -0,0 +1,160 @@
+%{
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hcid.h"
+#include "kword.h"
+#include "parser.h"
+
+static char str_buf[255];
+
+#define ECHO {;}
+#define YY_DECL int yylex(void)
+
+int cfg_error(const char *ftm, ...);
+int yyerror(char *str);
+
+%}
+
+%option nounput
+
+hex 0x[0-9a-zA-Z]+
+num [0-9]+
+kword [A-Za-z0-9\_\-]+
+word [A-Za-z0-9\-\_+=\!\$\#\%\&\*\^\@@\\\~\.]+
+wordnm {word}:{num}
+list ({word}\,*)+
+comment \#.*\n
+fname [A-Za-z0-9\_\.\-]+
+path (\/{fname})+
+string \".*\"
+hci hci[0-9]+
+hextuple [0-9a-zA-Z][0-9a-zA-Z]
+hexquad {hextuple}{hextuple}
+bdaddr {hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}:{hextuple}
+id {hexquad}:{hexquad}
+
+%x OPTION PARAM
+
+%%
+[ \t] {
+ /* Skip spaces and tabs */
+ ;
+}
+
+{comment} {
+ /* Skip comments */
+ lineno++;
+}
+
+\n {
+ lineno++;
+}
+
+{hci} {
+ yylval.str = yytext;
+ return HCI;
+}
+
+{bdaddr} {
+ yylval.str = yytext;
+ return BDADDR;
+}
+
+{hex} {
+ yylval.num = strtol(yytext, NULL, 16);
+ return NUM;
+}
+
+{num} {
+ yylval.num = atoi(yytext);
+ return NUM;
+}
+
+{kword} {
+ int kw = find_keyword(cfg_keyword, yytext);
+ if( kw != -1 )
+ return kw;
+
+ yylval.str = yytext;
+ return WORD;
+}
+
+{word} {
+ yylval.str = yytext;
+ return WORD;
+}
+
+{string} {
+ if (yyleng > sizeof(str_buf) - 1) {
+ yyerror("string too long");
+ return 0;
+ }
+
+ strncpy(str_buf, yytext + 1, yyleng - 2);
+ str_buf[yyleng - 2] = '\0';
+
+ yylval.str = str_buf;
+ return STRING;
+}
+
+{list} {
+ yylval.str = yytext;
+ return LIST;
+}
+
+{path} {
+ yylval.str = yytext;
+ return PATH;
+}
+
+{id} {
+ yylval.str = yytext;
+ return ID;
+}
+
+. {
+ return *yytext;
+}
+
+%%
+
+int yywrap(void)
+{
+ return 1;
+}
diff --git a/utils/hcid/list-devices b/utils/hcid/list-devices
new file mode 100755
index 00000000..ec6c580a
--- /dev/null
+++ b/utils/hcid/list-devices
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+def extract_uuids(uuid_list):
+ list = ""
+ for uuid in uuid_list:
+ if (uuid.endswith("-0000-1000-8000-00805f9b34fb")):
+ if (uuid.startswith("0000")):
+ val = "0x" + uuid[4:8]
+ else:
+ val = "0x" + uuid[0:8]
+ else:
+ val = str(uuid)
+ list = list + val + " "
+ return list
+
+adapter_list = manager.ListAdapters()
+
+for i in adapter_list:
+ adapter = dbus.Interface(bus.get_object("org.bluez", i),
+ "org.bluez.Adapter")
+ print "[ " + i + " ]"
+
+ properties = adapter.GetProperties()
+ for key in properties.keys():
+ print " %s = %s" % (key, properties[key])
+
+ device_list = adapter.ListDevices()
+
+ for n in device_list:
+ device = dbus.Interface(bus.get_object("org.bluez", n),
+ "org.bluez.Device")
+ print " [ " + n + " ]"
+
+ properties = device.GetProperties()
+ for key in properties.keys():
+ value = properties[key]
+ if (key == "UUIDs"):
+ list = extract_uuids(value)
+ print " %s = %s" % (key, list)
+ elif (key == "Class"):
+ print " %s = 0x%06x" % (key, value)
+ else:
+ print " %s = %s" % (key, value)
+
+ print
diff --git a/utils/hcid/main.c b/utils/hcid/main.c
new file mode 100644
index 00000000..f75f6c1f
--- /dev/null
+++ b/utils/hcid/main.c
@@ -0,0 +1,971 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include "hcid.h"
+#include "sdpd.h"
+#include "adapter.h"
+#include "dbus-common.h"
+#include "dbus-service.h"
+#include "dbus-database.h"
+#include "dbus-hci.h"
+#include "device.h"
+#include "agent.h"
+
+struct hcid_opts hcid;
+struct device_opts default_device;
+struct device_opts *parser_device;
+static struct device_list *device_list = NULL;
+static int child_pipe[2];
+
+static GKeyFile *load_config(const char *file)
+{
+ GError *err = NULL;
+ GKeyFile *keyfile;
+
+ 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_error_free(err);
+ g_key_file_free(keyfile);
+ return NULL;
+ }
+
+ return keyfile;
+}
+
+static inline void init_device_defaults(struct device_opts *device_opts)
+{
+ memset(device_opts, 0, sizeof(*device_opts));
+ device_opts->scan = SCAN_PAGE;
+ device_opts->mode = MODE_CONNECTABLE;
+ device_opts->name = g_strdup("BlueZ");
+ device_opts->discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT;
+}
+
+struct device_opts *alloc_device_opts(char *ref)
+{
+ struct device_list *device;
+
+ device = g_try_new(struct device_list, 1);
+ if (!device) {
+ info("Can't allocate devlist opts buffer: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ device->ref = g_strdup(ref);
+ device->next = device_list;
+ device_list = device;
+
+ memcpy(&device->opts, &default_device, sizeof(struct device_opts));
+ device->opts.name = g_strdup(default_device.name);
+
+ return &device->opts;
+}
+
+static void free_device_opts(void)
+{
+ struct device_list *device, *next;
+
+ g_free(default_device.name);
+
+ for (device = device_list; device; device = next) {
+ g_free(device->ref);
+ g_free(device->opts.name);
+ next = device->next;
+ g_free(device);
+ }
+
+ device_list = NULL;
+}
+
+static inline struct device_opts *find_device_opts(char *ref)
+{
+ struct device_list *device;
+
+ for (device = device_list; device; device = device->next)
+ if (!strcmp(ref, device->ref))
+ return &device->opts;
+
+ return NULL;
+}
+
+static struct device_opts *get_device_opts(int hdev)
+{
+ struct device_opts *device_opts = NULL;
+ struct hci_dev_info di;
+
+ /* First try to get BD_ADDR based settings ... */
+ if (hci_devinfo(hdev, &di) == 0) {
+ char addr[18];
+ ba2str(&di.bdaddr, addr);
+ device_opts = find_device_opts(addr);
+ }
+
+ /* ... then try HCI based settings ... */
+ if (!device_opts) {
+ char ref[8];
+ snprintf(ref, sizeof(ref) - 1, "hci%d", hdev);
+ device_opts = find_device_opts(ref);
+ }
+
+ /* ... and last use the default settings. */
+ if (!device_opts)
+ device_opts = &default_device;
+
+ return device_opts;
+}
+
+static struct device_opts *get_opts(int hdev)
+{
+ struct device_opts *device_opts = NULL;
+ struct hci_dev_info di;
+ char addr[18];
+ int sock;
+
+ if (hdev < 0)
+ return NULL;
+
+ sock = hci_open_dev(hdev);
+ if (sock < 0)
+ goto no_address;
+
+ if (hci_devinfo(hdev, &di) < 0) {
+ close(sock);
+ goto no_address;
+ }
+
+ close(sock);
+
+ ba2str(&di.bdaddr, addr);
+ device_opts = find_device_opts(addr);
+
+no_address:
+ if (!device_opts) {
+ char ref[8];
+ snprintf(ref, sizeof(ref) - 1, "hci%d", hdev);
+ device_opts = find_device_opts(ref);
+ }
+
+ if (!device_opts)
+ device_opts = &default_device;
+
+ return device_opts;
+}
+
+uint8_t get_startup_scan(int hdev)
+{
+ struct device_opts *device_opts = get_opts(hdev);
+ if (!device_opts)
+ return SCAN_DISABLED;
+
+ return device_opts->scan;
+}
+
+uint8_t get_startup_mode(int hdev)
+{
+ struct device_opts *device_opts = get_opts(hdev);
+ if (!device_opts)
+ return MODE_OFF;
+
+ return device_opts->mode;
+}
+
+int get_discoverable_timeout(int hdev)
+{
+ struct device_opts *device_opts = NULL;
+ struct hci_dev_info di;
+ char addr[18];
+ int sock, timeout;
+
+ if (hdev < 0)
+ return HCID_DEFAULT_DISCOVERABLE_TIMEOUT;
+
+ sock = hci_open_dev(hdev);
+ if (sock < 0)
+ goto no_address;
+
+ if (hci_devinfo(hdev, &di) < 0) {
+ close(sock);
+ goto no_address;
+ }
+
+ close(sock);
+
+ if (read_discoverable_timeout(&di.bdaddr, &timeout) == 0)
+ return timeout;
+
+ ba2str(&di.bdaddr, addr);
+ device_opts = find_device_opts(addr);
+
+no_address:
+ if (!device_opts) {
+ char ref[8];
+ snprintf(ref, sizeof(ref) - 1, "hci%d", hdev);
+ device_opts = find_device_opts(ref);
+ }
+
+ if (!device_opts)
+ device_opts = &default_device;
+
+ return device_opts->discovto;
+}
+
+void update_service_classes(const bdaddr_t *bdaddr, uint8_t value)
+{
+ struct hci_dev_list_req *dl;
+ struct hci_dev_req *dr;
+ int i, sk;
+
+ sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (sk < 0)
+ return;
+
+ dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl));
+
+ dl->dev_num = HCI_MAX_DEV;
+ dr = dl->dev_req;
+
+ if (ioctl(sk, HCIGETDEVLIST, dl) < 0) {
+ close(sk);
+ g_free(dl);
+ return;
+ }
+
+ dr = dl->dev_req;
+
+ for (i = 0; i < dl->dev_num; i++, dr++) {
+ struct hci_dev_info di;
+ uint8_t cls[3];
+ int dd;
+
+ if (hci_devinfo(dr->dev_id, &di) < 0)
+ continue;
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ continue;
+
+ if (!hci_test_bit(HCI_UP, &di.flags))
+ continue;
+
+ if (get_device_class(di.dev_id, cls) < 0)
+ continue;
+
+ dd = hci_open_dev(di.dev_id);
+ if (dd < 0)
+ continue;
+
+ set_service_classes(dd, cls, value);
+
+ hci_close_dev(dd);
+
+ update_adapter(di.dev_id);
+ }
+
+ g_free(dl);
+
+ close(sk);
+}
+
+/*
+ * Device name expansion
+ * %d - device id
+ */
+static char *expand_name(char *dst, int size, char *str, int dev_id)
+{
+ register int sp, np, olen;
+ char *opt, buf[10];
+
+ if (!str && !dst)
+ return NULL;
+
+ sp = np = 0;
+ while (np < size - 1 && str[sp]) {
+ switch (str[sp]) {
+ case '%':
+ opt = NULL;
+
+ switch (str[sp+1]) {
+ case 'd':
+ sprintf(buf, "%d", dev_id);
+ opt = buf;
+ break;
+
+ case 'h':
+ opt = hcid.host_name;
+ break;
+
+ case '%':
+ dst[np++] = str[sp++];
+ /* fall through */
+ default:
+ sp++;
+ continue;
+ }
+
+ if (opt) {
+ /* substitute */
+ olen = strlen(opt);
+ if (np + olen < size - 1)
+ memcpy(dst + np, opt, olen);
+ np += olen;
+ }
+ sp += 2;
+ continue;
+
+ case '\\':
+ sp++;
+ /* fall through */
+ default:
+ dst[np++] = str[sp++];
+ break;
+ }
+ }
+ dst[np] = '\0';
+ return dst;
+}
+
+static gboolean child_exit(GIOChannel *io, GIOCondition cond, void *user_data)
+{
+ int status, fd = g_io_channel_unix_get_fd(io);
+ pid_t child_pid;
+
+ if (read(fd, &child_pid, sizeof(child_pid)) != sizeof(child_pid)) {
+ error("child_exit: unable to read child pid from pipe");
+ return TRUE;
+ }
+
+ if (waitpid(child_pid, &status, 0) != child_pid)
+ error("waitpid(%d) failed", child_pid);
+ else
+ debug("child %d exited", child_pid);
+
+ return TRUE;
+}
+
+static void at_child_exit(void)
+{
+ pid_t pid = getpid();
+
+ if (write(child_pipe[1], &pid, sizeof(pid)) != sizeof(pid))
+ error("unable to write to child pipe");
+}
+
+static void configure_device(int dev_id)
+{
+ struct device_opts *device_opts;
+ struct hci_dev_req dr;
+ struct hci_dev_info di;
+ char mode[14];
+ int dd;
+
+ device_opts = get_device_opts(dev_id);
+
+ if (hci_devinfo(dev_id, &di) < 0)
+ return;
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ return;
+
+ /* Set default discoverable timeout if not set */
+ if (!(device_opts->flags & (1 << HCID_SET_DISCOVTO)))
+ device_opts->discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT;
+
+ /* Set scan mode */
+ if (read_device_mode(&di.bdaddr, mode, sizeof(mode)) == 0) {
+ if (!strcmp(mode, "off") && hcid.offmode == HCID_OFFMODE_NOSCAN) {
+ device_opts->mode = MODE_OFF;
+ device_opts->scan = SCAN_DISABLED;
+ } else if (!strcmp(mode, "connectable")) {
+ device_opts->mode = MODE_CONNECTABLE;
+ device_opts->scan = SCAN_PAGE;
+ } else if (!strcmp(mode, "discoverable")) {
+ /* Set discoverable only if timeout is 0 */
+ if (!get_discoverable_timeout(dev_id)) {
+ device_opts->scan = SCAN_PAGE | SCAN_INQUIRY;
+ device_opts->mode = MODE_DISCOVERABLE;
+ } else {
+ device_opts->scan = SCAN_PAGE;
+ device_opts->mode = MODE_CONNECTABLE;
+ }
+ } else if (!strcmp(mode, "limited")) {
+ /* Set discoverable only if timeout is 0 */
+ if (!get_discoverable_timeout(dev_id)) {
+ device_opts->scan = SCAN_PAGE | SCAN_INQUIRY;
+ device_opts->mode = MODE_LIMITED;
+ } else {
+ device_opts->scan = SCAN_PAGE;
+ device_opts->mode = MODE_CONNECTABLE;
+ }
+ }
+ }
+
+ /* Do configuration in the separate process */
+ switch (fork()) {
+ case 0:
+ atexit(at_child_exit);
+ break;
+ case -1:
+ error("Fork failed. Can't init device hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ default:
+ return;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ exit(1);
+ }
+
+ memset(&dr, 0, sizeof(dr));
+ dr.dev_id = dev_id;
+
+ /* Set packet type */
+ if ((device_opts->flags & (1 << HCID_SET_PTYPE))) {
+ dr.dev_opt = device_opts->pkt_type;
+ if (ioctl(dd, HCISETPTYPE, (unsigned long) &dr) < 0) {
+ error("Can't set packet type on hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ }
+ }
+
+ /* Set link mode */
+ if ((device_opts->flags & (1 << HCID_SET_LM))) {
+ dr.dev_opt = device_opts->link_mode;
+ if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0) {
+ error("Can't set link mode on hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ }
+ }
+
+ /* Set link policy */
+ if ((device_opts->flags & (1 << HCID_SET_LP))) {
+ dr.dev_opt = device_opts->link_policy;
+ if (ioctl(dd, HCISETLINKPOL, (unsigned long) &dr) < 0) {
+ error("Can't set link policy on hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ }
+ }
+
+ /* Set device name */
+ if ((device_opts->flags & (1 << HCID_SET_NAME)) && device_opts->name) {
+ change_local_name_cp cp;
+
+ memset(cp.name, 0, sizeof(cp.name));
+ expand_name((char *) cp.name, sizeof(cp.name),
+ device_opts->name, dev_id);
+
+ hci_send_cmd(dd, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
+ CHANGE_LOCAL_NAME_CP_SIZE, &cp);
+ }
+
+ /* Set device class */
+ if ((device_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(device_opts->class);
+ cls[2] = get_service_classes(&di.bdaddr);
+ memcpy(cp.dev_class, &class, 3);
+ } else {
+ if (!(device_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 ((device_opts->flags & (1 << HCID_SET_PAGETO))) {
+ write_page_timeout_cp cp;
+
+ cp.timeout = htobs(device_opts->pageto);
+ hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT,
+ WRITE_PAGE_TIMEOUT_CP_SIZE, &cp);
+ }
+
+ /* Set voice setting */
+ if ((device_opts->flags & (1 << HCID_SET_VOICE))) {
+ write_voice_setting_cp cp;
+
+ cp.voice_setting = htobl(device_opts->voice);
+ hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING,
+ WRITE_VOICE_SETTING_CP_SIZE, &cp);
+ }
+
+ exit(0);
+}
+
+static void init_device(int dev_id)
+{
+ struct hci_dev_info di;
+ int dd;
+
+ /* Do initialization in the separate process */
+ switch (fork()) {
+ case 0:
+ atexit(at_child_exit);
+ break;
+ case -1:
+ error("Fork failed. Can't init device hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ default:
+ return;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ error("Can't open device hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Start HCI device */
+ if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) {
+ error("Can't init device hci%d: %s (%d)",
+ dev_id, strerror(errno), errno);
+ goto fail;
+ }
+
+ if (hci_devinfo(dev_id, &di) < 0)
+ goto fail;
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ goto done;
+
+ if (hcid.offmode == HCID_OFFMODE_DEVDOWN) {
+ char mode[16];
+
+ if (read_device_mode(&di.bdaddr, mode, sizeof(mode)) == 0 &&
+ strcmp(mode, "off") == 0) {
+ ioctl(dd, HCIDEVDOWN, dev_id);
+ goto done;
+ }
+ }
+
+done:
+ hci_close_dev(dd);
+ exit(0);
+
+fail:
+ hci_close_dev(dd);
+ exit(1);
+}
+
+static void device_devreg_setup(int dev_id)
+{
+ struct hci_dev_info di;
+
+ if (hcid.auto_init)
+ init_device(dev_id);
+
+ if (hci_devinfo(dev_id, &di) < 0)
+ return;
+
+ if (!hci_test_bit(HCI_RAW, &di.flags))
+ hcid_dbus_register_device(dev_id);
+}
+
+static void device_devup_setup(int dev_id)
+{
+ add_adapter(dev_id);
+ if (hcid.auto_init)
+ configure_device(dev_id);
+ if (hcid.security)
+ start_security_manager(dev_id);
+ start_adapter(dev_id);
+ hcid_dbus_start_device(dev_id);
+}
+
+static void init_all_devices(int ctl)
+{
+ struct hci_dev_list_req *dl;
+ struct hci_dev_req *dr;
+ int i;
+
+ dl = g_try_malloc0(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
+ if (!dl) {
+ info("Can't allocate devlist buffer: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ dl->dev_num = HCI_MAX_DEV;
+ dr = dl->dev_req;
+
+ if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
+ info("Can't get device list: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ for (i = 0; i < dl->dev_num; i++, dr++) {
+ info("HCI dev %d registered", dr->dev_id);
+ device_devreg_setup(dr->dev_id);
+ if (hci_test_bit(HCI_UP, &dr->dev_opt)) {
+ info("HCI dev %d already up", dr->dev_id);
+ device_devup_setup(dr->dev_id);
+ }
+ }
+
+ g_free(dl);
+}
+
+static void init_defaults(void)
+{
+ hcid.auto_init = 1;
+ hcid.security = HCID_SEC_AUTO;
+
+ init_device_defaults(&default_device);
+}
+
+static inline void device_event(GIOChannel *chan, evt_stack_internal *si)
+{
+ evt_si_device *sd = (void *) &si->data;
+
+ switch (sd->event) {
+ case HCI_DEV_REG:
+ info("HCI dev %d registered", sd->dev_id);
+ device_devreg_setup(sd->dev_id);
+ break;
+
+ case HCI_DEV_UNREG:
+ info("HCI dev %d unregistered", sd->dev_id);
+ hcid_dbus_unregister_device(sd->dev_id);
+ remove_adapter(sd->dev_id);
+ break;
+
+ case HCI_DEV_UP:
+ info("HCI dev %d up", sd->dev_id);
+ device_devup_setup(sd->dev_id);
+ break;
+
+ case HCI_DEV_DOWN:
+ info("HCI dev %d down", sd->dev_id);
+ hcid_dbus_stop_device(sd->dev_id);
+ if (hcid.security)
+ stop_security_manager(sd->dev_id);
+ stop_adapter(sd->dev_id);
+ break;
+ }
+}
+
+static gboolean io_stack_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
+ evt_stack_internal *si;
+ hci_event_hdr *eh;
+ int type;
+ size_t len;
+ GIOError err;
+
+ ptr = buf;
+
+ if ((err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len))) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+
+ error("Read from control socket failed: %s (%d)",
+ strerror(errno), errno);
+ return FALSE;
+ }
+
+ type = *ptr++;
+
+ if (type != HCI_EVENT_PKT)
+ return TRUE;
+
+ eh = (hci_event_hdr *) ptr;
+ if (eh->evt != EVT_STACK_INTERNAL)
+ return TRUE;
+
+ ptr += HCI_EVENT_HDR_SIZE;
+
+ si = (evt_stack_internal *) ptr;
+ switch (si->type) {
+ case EVT_SI_DEVICE:
+ device_event(chan, si);
+ break;
+ }
+
+ return TRUE;
+}
+
+static GMainLoop *event_loop;
+
+static void sig_term(int sig)
+{
+ g_main_loop_quit(event_loop);
+}
+
+static void sig_hup(int sig)
+{
+ info("Reloading config file");
+
+ free_device_opts();
+
+ init_defaults();
+
+ if (read_config(hcid.config_file) < 0)
+ error("Config reload failed");
+
+ init_security_data();
+
+ init_all_devices(hcid.sock);
+}
+
+static void sig_debug(int sig)
+{
+ toggle_debug();
+}
+
+static void usage(void)
+{
+ printf("hcid - HCI daemon ver %s\n", VERSION);
+ printf("Usage: \n");
+ printf("\thcid [-n] [-d] [-m mtu] [-f config file]\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct sockaddr_hci addr;
+ struct hci_filter flt;
+ struct sigaction sa;
+ GIOChannel *ctl_io, *child_io;
+ uint16_t mtu = 0;
+ int opt, daemonize = 1, debug = 0, sdp = 1, experimental = 0;
+ GKeyFile *config;
+
+ /* Default HCId settings */
+ memset(&hcid, 0, sizeof(hcid));
+ hcid.auto_init = 1;
+ hcid.config_file = HCID_CONFIG_FILE;
+ hcid.security = HCID_SEC_AUTO;
+ hcid.pairing = HCID_PAIRING_MULTI;
+ hcid.offmode = HCID_OFFMODE_NOSCAN;
+
+ if (gethostname(hcid.host_name, sizeof(hcid.host_name) - 1) < 0)
+ strcpy(hcid.host_name, "noname");
+
+ strcpy((char *) hcid.pin_code, "BlueZ");
+ hcid.pin_len = 5;
+
+ init_defaults();
+
+ while ((opt = getopt(argc, argv, "ndsm:xf:")) != EOF) {
+ switch (opt) {
+ case 'n':
+ daemonize = 0;
+ break;
+
+ case 'd':
+ debug = 1;
+ break;
+
+ case 's':
+ sdp = 1;
+ break;
+
+ case 'm':
+ mtu = atoi(optarg);
+ break;
+
+ case 'x':
+ experimental = 1;
+ break;
+
+ case 'f':
+ hcid.config_file = g_strdup(optarg);
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (daemonize && daemon(0, 0)) {
+ error("Can't daemonize: %s (%d)", strerror(errno), errno);
+ exit(1);
+ }
+
+ umask(0077);
+
+ start_logging("hcid", "Bluetooth HCI daemon");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sa.sa_handler = sig_debug;
+ sigaction(SIGUSR2, &sa, NULL);
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sa, NULL);
+
+ if (debug) {
+ info("Enabling debug information");
+ enable_debug();
+ }
+
+ /* Create and bind HCI socket */
+ if ((hcid.sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
+ error("Can't open HCI socket: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Set filter */
+ hci_filter_clear(&flt);
+ hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
+ hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
+ if (setsockopt(hcid.sock, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+ error("Can't set filter: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = HCI_DEV_NONE;
+ if (bind(hcid.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ error("Can't bind HCI socket: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ config = load_config(CONFIGDIR "/main.conf");
+
+ if (read_config(hcid.config_file) < 0)
+ error("Config load failed");
+
+ if (pipe(child_pipe) < 0) {
+ error("pipe(): %s (%d)", strerror(errno), errno);
+ exit(1);
+ }
+
+ child_io = g_io_channel_unix_new(child_pipe[0]);
+ g_io_channel_set_close_on_unref(child_io, TRUE);
+ g_io_add_watch(child_io,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ child_exit, NULL);
+ g_io_channel_unref(child_io);
+
+ init_adapters();
+
+ agent_init();
+
+ if (experimental)
+ hcid_dbus_set_experimental();
+
+ if (hcid_dbus_init() < 0) {
+ error("Unable to get on D-Bus");
+ exit(1);
+ }
+
+ start_sdp_server(mtu, hcid.deviceid, SDP_SERVER_COMPAT);
+ set_service_classes_callback(update_service_classes);
+
+ /* Loading plugins has to be done after D-Bus has been setup since
+ * the plugins might wanna expose some paths on the bus. However the
+ * best order of how to init various subsystems of the Bluetooth
+ * daemon needs to be re-worked. */
+ plugin_init(config);
+
+ init_security_data();
+
+ event_loop = g_main_loop_new(NULL, FALSE);
+
+ ctl_io = g_io_channel_unix_new(hcid.sock);
+ g_io_channel_set_close_on_unref(ctl_io, TRUE);
+
+ g_io_add_watch(ctl_io, G_IO_IN, io_stack_event, NULL);
+
+ g_io_channel_unref(ctl_io);
+
+ /* Initialize already connected devices */
+ init_all_devices(hcid.sock);
+
+ g_main_loop_run(event_loop);
+
+ hcid_dbus_unregister();
+
+ plugin_cleanup();
+
+ stop_sdp_server();
+
+ free_device_opts();
+
+ agent_exit();
+
+ hcid_dbus_exit();
+
+ g_main_loop_unref(event_loop);
+
+ if (config)
+ g_key_file_free(config);
+
+ info("Exit");
+
+ stop_logging();
+
+ return 0;
+}
diff --git a/utils/hcid/manager.c b/utils/hcid/manager.c
new file mode 100644
index 00000000..c2d5fdf1
--- /dev/null
+++ b/utils/hcid/manager.c
@@ -0,0 +1,683 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include <gdbus.h>
+
+#include "hcid.h"
+#include "sdpd.h"
+#include "adapter.h"
+#include "dbus-common.h"
+#include "error.h"
+#include "dbus-error.h"
+#include "dbus-hci.h"
+#include "dbus-service.h"
+#include "dbus-database.h"
+#include "dbus-security.h"
+#include "sdp-xml.h"
+
+#include "manager.h"
+
+static DBusConnection *connection = NULL;
+static int default_adapter_id = -1;
+static GSList *adapters = NULL;
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+}
+
+static inline DBusMessage *no_such_adapter(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NoSuchAdapter",
+ "No such adapter");
+}
+
+static inline DBusMessage *no_such_service(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NoSuchService",
+ "No such service");
+}
+
+static inline DBusMessage *failed_strerror(DBusMessage *msg, int err)
+{
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".Failed",
+ strerror(err));
+}
+
+static DBusMessage *interface_version(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ dbus_uint32_t version = 0;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, &version,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *old_default_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ char path[MAX_PATH_LENGTH], *path_ptr = path;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ if (default_adapter_id < 0)
+ return no_such_adapter(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, default_adapter_id);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static int find_by_address(const char *str)
+{
+ struct hci_dev_list_req *dl;
+ struct hci_dev_req *dr;
+ bdaddr_t ba;
+ int i, sk;
+ int devid = -1;
+
+ sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (sk < 0)
+ return -1;
+
+ dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl));
+
+ dl->dev_num = HCI_MAX_DEV;
+ dr = dl->dev_req;
+
+ if (ioctl(sk, HCIGETDEVLIST, dl) < 0)
+ goto out;
+
+ dr = dl->dev_req;
+ str2ba(str, &ba);
+
+ for (i = 0; i < dl->dev_num; i++, dr++) {
+ struct hci_dev_info di;
+
+ if (hci_devinfo(dr->dev_id, &di) < 0)
+ continue;
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ continue;
+
+ if (!bacmp(&ba, &di.bdaddr)) {
+ devid = dr->dev_id;
+ break;
+ }
+ }
+
+out:
+ g_free(dl);
+ close(sk);
+ return devid;
+}
+
+static DBusMessage *old_find_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ char path[MAX_PATH_LENGTH], *path_ptr = path;
+ struct hci_dev_info di;
+ const char *pattern;
+ int dev_id;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ /* hci_devid() would make sense to use here, except it
+ is restricted to devices which are up */
+ if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4)
+ dev_id = atoi(pattern + 3);
+ else
+ dev_id = find_by_address(pattern);
+
+ if (dev_id < 0)
+ return no_such_adapter(msg);
+
+ if (hci_devinfo(dev_id, &di) < 0)
+ return no_such_adapter(msg);
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ return no_such_adapter(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, dev_id);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path_ptr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *old_list_adapters(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ DBusMessage *reply;
+ struct hci_dev_list_req *dl;
+ struct hci_dev_req *dr;
+ int i, sk;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (sk < 0)
+ return failed_strerror(msg, errno);
+
+ dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl));
+
+ dl->dev_num = HCI_MAX_DEV;
+ dr = dl->dev_req;
+
+ if (ioctl(sk, HCIGETDEVLIST, dl) < 0) {
+ int err = errno;
+ close(sk);
+ g_free(dl);
+ return failed_strerror(msg, err);
+ }
+
+ dr = dl->dev_req;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ close(sk);
+ g_free(dl);
+ return NULL;
+ }
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ for (i = 0; i < dl->dev_num; i++, dr++) {
+ char path[MAX_PATH_LENGTH], *path_ptr = path;
+ struct hci_dev_info di;
+
+ if (hci_devinfo(dr->dev_id, &di) < 0)
+ continue;
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", BASE_PATH, di.name);
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &path_ptr);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ g_free(dl);
+
+ close(sk);
+
+ return reply;
+}
+
+static DBusMessage *find_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *pattern;
+ struct service *service;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ service = search_service(pattern);
+ if (!service)
+ return no_such_service(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &service->object_path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *list_services(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return invalid_args(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ append_available_services(&array_iter);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static DBusMessage *activate_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *pattern;
+ struct service *service;
+ const char *busname = "org.bluez";
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return invalid_args(msg);
+
+ service = search_service(pattern);
+ if (!service)
+ return no_such_service(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &busname,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static GDBusMethodTable old_manager_methods[] = {
+ { "InterfaceVersion", "", "u", interface_version },
+ { "DefaultAdapter", "", "s", old_default_adapter },
+ { "FindAdapter", "s", "s", old_find_adapter },
+ { "ListAdapters", "", "as", old_list_adapters },
+ { "FindService", "s", "s", find_service },
+ { "ListServices", "", "as", list_services },
+ { "ActivateService", "s", "s", activate_service },
+ { NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable old_manager_signals[] = {
+ { "AdapterAdded", "s" },
+ { "AdapterRemoved", "s" },
+ { "DefaultAdapterChanged", "s" },
+ { "ServiceAdded", "s" },
+ { "ServiceRemoved", "s" },
+ { NULL, NULL }
+};
+
+static DBusMessage *default_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ struct adapter *adapter;
+ char *path;
+
+ adapter = manager_find_adapter_by_id(default_adapter_id);
+ if (!adapter)
+ return no_such_adapter(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ path = adapter->path + ADAPTER_PATH_INDEX;
+
+ dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *find_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ struct adapter *adapter;
+ char *path;
+ struct hci_dev_info di;
+ const char *pattern;
+ int dev_id;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ /* hci_devid() would make sense to use here, except it
+ is restricted to devices which are up */
+ if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4)
+ dev_id = atoi(pattern + 3);
+ else
+ dev_id = find_by_address(pattern);
+
+ if (dev_id < 0)
+ return no_such_adapter(msg);
+
+ if (hci_devinfo(dev_id, &di) < 0)
+ return no_such_adapter(msg);
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ return no_such_adapter(msg);
+
+ adapter = manager_find_adapter_by_id(dev_id);
+ if (!adapter)
+ return no_such_adapter(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ path = adapter->path + ADAPTER_PATH_INDEX;
+
+ dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *list_adapters(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ DBusMessage *reply;
+ GSList *l;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+
+ for (l = adapters; l; l = l->next) {
+ struct adapter *adapter = l->data;
+ char *path;
+ struct hci_dev_info di;
+
+ if (hci_devinfo(adapter->dev_id, &di) < 0)
+ continue;
+
+ if (hci_test_bit(HCI_RAW, &di.flags))
+ continue;
+
+ path = adapter->path + ADAPTER_PATH_INDEX;
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_OBJECT_PATH, &path);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static GDBusMethodTable manager_methods[] = {
+ { "DefaultAdapter", "", "o", default_adapter },
+ { "FindAdapter", "s", "o", find_adapter },
+ { "ListAdapters", "", "ao", list_adapters },
+ { }
+};
+
+static GDBusSignalTable manager_signals[] = {
+ { "AdapterAdded", "o" },
+ { "AdapterRemoved", "o" },
+ { "DefaultAdapterChanged", "o" },
+ { }
+};
+
+dbus_bool_t manager_init(DBusConnection *conn, const char *path)
+{
+ connection = conn;
+
+ if (hcid_dbus_use_experimental()) {
+ debug("Registering experimental manager interface");
+ g_dbus_register_interface(conn, "/", MANAGER_INTERFACE,
+ manager_methods, manager_signals,
+ NULL, NULL, NULL);
+ }
+
+ return g_dbus_register_interface(conn, path, MANAGER_INTERFACE,
+ old_manager_methods, old_manager_signals,
+ NULL, NULL, NULL);
+}
+
+void manager_cleanup(DBusConnection *conn, const char *path)
+{
+ g_dbus_unregister_interface(conn, path, MANAGER_INTERFACE);
+
+ if (hcid_dbus_use_experimental())
+ g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE);
+}
+
+static gint adapter_id_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct adapter *adapter = a;
+ uint16_t id = GPOINTER_TO_UINT(b);
+
+ return adapter->dev_id == id ? 0 : -1;
+}
+
+static gint adapter_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct adapter *adapter = a;
+ const char *path = b;
+
+ return strcmp(adapter->path, path);
+}
+
+static gint adapter_address_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct adapter *adapter = a;
+ const char *address = b;
+
+ return strcmp(adapter->address, address);
+}
+
+struct adapter *manager_find_adapter(const bdaddr_t *sba)
+{
+ GSList *match;
+ char address[18];
+
+ ba2str(sba, address);
+
+ match = g_slist_find_custom(adapters, address, adapter_address_cmp);
+ if (!match)
+ return NULL;
+
+ return match->data;
+}
+
+struct adapter *manager_find_adapter_by_path(const char *path)
+{
+ GSList *match;
+
+ match = g_slist_find_custom(adapters, path, adapter_path_cmp);
+ if (!match)
+ return NULL;
+
+ return match->data;
+}
+
+struct adapter *manager_find_adapter_by_id(int id)
+{
+ GSList *match;
+
+ match = g_slist_find_custom(adapters, GINT_TO_POINTER(id), adapter_id_cmp);
+ if (!match)
+ return NULL;
+
+ return match->data;
+}
+
+void manager_add_adapter(struct adapter *adapter)
+{
+ const char *ptr = adapter->path + ADAPTER_PATH_INDEX;
+
+ if (hcid_dbus_use_experimental()) {
+ g_dbus_emit_signal(connection, "/",
+ MANAGER_INTERFACE, "AdapterAdded",
+ DBUS_TYPE_OBJECT_PATH, &ptr,
+ DBUS_TYPE_INVALID);
+ }
+
+ g_dbus_emit_signal(connection, BASE_PATH,
+ MANAGER_INTERFACE, "AdapterAdded",
+ DBUS_TYPE_STRING, &adapter->path,
+ DBUS_TYPE_INVALID);
+
+ adapters = g_slist_append(adapters, adapter);
+}
+
+void manager_remove_adapter(struct adapter *adapter)
+{
+ const char *ptr = adapter->path + ADAPTER_PATH_INDEX;
+
+ if (hcid_dbus_use_experimental()) {
+ g_dbus_emit_signal(connection, "/",
+ MANAGER_INTERFACE, "AdapterRemoved",
+ DBUS_TYPE_OBJECT_PATH, &ptr,
+ DBUS_TYPE_INVALID);
+ }
+
+ g_dbus_emit_signal(connection, BASE_PATH,
+ MANAGER_INTERFACE, "AdapterRemoved",
+ DBUS_TYPE_STRING, &adapter->path,
+ DBUS_TYPE_INVALID);
+
+ if ((default_adapter_id == adapter->dev_id || default_adapter_id < 0)) {
+ int new_default = hci_get_route(NULL);
+
+ default_adapter_id = new_default;
+ if (new_default >= 0) {
+ if (hcid_dbus_use_experimental()) {
+ g_dbus_emit_signal(connection, "/",
+ MANAGER_INTERFACE,
+ "DefaultAdapterChanged",
+ DBUS_TYPE_OBJECT_PATH, &ptr,
+ DBUS_TYPE_INVALID);
+ }
+ g_dbus_emit_signal(connection, BASE_PATH,
+ MANAGER_INTERFACE,
+ "DefaultAdapterChanged",
+ DBUS_TYPE_STRING, &adapter->path,
+ DBUS_TYPE_INVALID);
+ } else {
+ g_dbus_emit_signal(connection, BASE_PATH,
+ MANAGER_INTERFACE,
+ "DefaultAdapterChanged",
+ DBUS_TYPE_STRING, &adapter->path,
+ DBUS_TYPE_INVALID);
+ }
+ }
+
+ adapters = g_slist_remove(adapters, adapter);
+}
+
+int manager_get_default_adapter()
+{
+ return default_adapter_id;
+}
+
+void manager_set_default_adapter(int id)
+{
+ struct adapter *adapter = manager_find_adapter_by_id(id);
+ const char *ptr = adapter->path + ADAPTER_PATH_INDEX;
+
+ default_adapter_id = id;
+
+ if (hcid_dbus_use_experimental())
+ g_dbus_emit_signal(connection, "/",
+ MANAGER_INTERFACE,
+ "DefaultAdapterChanged",
+ DBUS_TYPE_OBJECT_PATH, &ptr,
+ DBUS_TYPE_INVALID);
+
+ g_dbus_emit_signal(connection, BASE_PATH,
+ MANAGER_INTERFACE,
+ "DefaultAdapterChanged",
+ DBUS_TYPE_STRING, &adapter->path,
+ DBUS_TYPE_INVALID);
+}
diff --git a/utils/hcid/manager.h b/utils/hcid/manager.h
new file mode 100644
index 00000000..2065d5ac
--- /dev/null
+++ b/utils/hcid/manager.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define MANAGER_INTERFACE "org.bluez.Manager"
+
+dbus_bool_t manager_init(DBusConnection *conn, const char *path);
+void manager_cleanup(DBusConnection *conn, const char *path);
+
+struct adapter *manager_find_adapter(const bdaddr_t *sba);
+struct adapter *manager_find_adapter_by_path(const char *path);
+struct adapter *manager_find_adapter_by_id(int id);
+void manager_add_adapter(struct adapter *adapter);
+void manager_remove_adapter(struct adapter *adapter);
+int manager_get_default_adapter();
+void manager_set_default_adapter(int id);
diff --git a/utils/hcid/parser.c b/utils/hcid/parser.c
new file mode 100644
index 00000000..af5ba448
--- /dev/null
+++ b/utils/hcid/parser.c
@@ -0,0 +1,2084 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ K_OPTIONS = 258,
+ K_DEVICE = 259,
+ K_AUTOINIT = 260,
+ K_SECURITY = 261,
+ K_PAIRING = 262,
+ K_OFFMODE = 263,
+ K_DEVICEID = 264,
+ K_PTYPE = 265,
+ K_NAME = 266,
+ K_CLASS = 267,
+ K_VOICE = 268,
+ K_PAGETO = 269,
+ K_LM = 270,
+ K_LP = 271,
+ K_ISCAN = 272,
+ K_PSCAN = 273,
+ K_DISCOVTO = 274,
+ K_PASSKEY = 275,
+ K_YES = 276,
+ K_NO = 277,
+ WORD = 278,
+ PATH = 279,
+ STRING = 280,
+ LIST = 281,
+ HCI = 282,
+ BDADDR = 283,
+ ID = 284,
+ NUM = 285
+ };
+#endif
+/* Tokens. */
+#define K_OPTIONS 258
+#define K_DEVICE 259
+#define K_AUTOINIT 260
+#define K_SECURITY 261
+#define K_PAIRING 262
+#define K_OFFMODE 263
+#define K_DEVICEID 264
+#define K_PTYPE 265
+#define K_NAME 266
+#define K_CLASS 267
+#define K_VOICE 268
+#define K_PAGETO 269
+#define K_LM 270
+#define K_LP 271
+#define K_ISCAN 272
+#define K_PSCAN 273
+#define K_DISCOVTO 274
+#define K_PASSKEY 275
+#define K_YES 276
+#define K_NO 277
+#define WORD 278
+#define PATH 279
+#define STRING 280
+#define LIST 281
+#define HCI 282
+#define BDADDR 283
+#define ID 284
+#define NUM 285
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "parser.y"
+
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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 <stdarg.h>
+
+#include <sys/socket.h>
+#include <asm/types.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hcid.h"
+#include "kword.h"
+
+int cfg_error(const char *fmt, ...);
+
+int yyparse(void);
+int yylex(void);
+int yyerror(char *s);
+
+void yylex_destroy(void);
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 59 "parser.y"
+{
+ char *str;
+ long num;
+}
+/* Line 187 of yacc.c. */
+#line 219 "parser.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 232 "parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 14
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 85
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 34
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 21
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 55
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 83
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 285
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 33,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 31, 2, 32, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 5, 8, 11, 14, 16, 18, 20,
+ 23, 26, 30, 31, 34, 37, 41, 44, 47, 50,
+ 53, 56, 59, 61, 63, 65, 67, 69, 71, 75,
+ 76, 79, 82, 86, 89, 92, 95, 98, 101, 104,
+ 107, 110, 113, 116, 118, 120, 122, 124, 126, 128,
+ 130, 132, 134, 136, 138, 140
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 35, 0, -1, 36, -1, 35, 36, -1, 3, 38,
+ -1, 37, 45, -1, 23, -1, 1, -1, 4, -1,
+ 4, 49, -1, 4, 50, -1, 31, 39, 32, -1,
+ -1, 40, 33, -1, 1, 33, -1, 39, 40, 33,
+ -1, 5, 54, -1, 6, 41, -1, 7, 42, -1,
+ 8, 43, -1, 9, 44, -1, 20, 25, -1, 23,
+ -1, 23, -1, 22, -1, 23, -1, 23, -1, 29,
+ -1, 31, 46, 32, -1, -1, 47, 33, -1, 1,
+ 33, -1, 46, 47, 33, -1, 10, 51, -1, 15,
+ 52, -1, 16, 53, -1, 11, 48, -1, 12, 30,
+ -1, 13, 30, -1, 14, 30, -1, 19, 30, -1,
+ 17, 54, -1, 18, 54, -1, 23, -1, 23, -1,
+ 25, -1, 27, -1, 28, -1, 23, -1, 26, -1,
+ 23, -1, 26, -1, 23, -1, 26, -1, 21, -1,
+ 22, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 77, 77, 77, 79, 81, 83, 87, 93, 97,
+ 101, 106, 107, 107, 107, 107, 109, 113, 117, 121,
+ 125, 129, 137, 143, 152, 158, 169, 180, 184, 185,
+ 185, 185, 185, 187, 192, 197, 202, 209, 214, 219,
+ 224, 229, 236, 243, 250, 254, 260, 266, 272, 279,
+ 288, 295, 304, 311, 319, 319
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "K_OPTIONS", "K_DEVICE", "K_AUTOINIT",
+ "K_SECURITY", "K_PAIRING", "K_OFFMODE", "K_DEVICEID", "K_PTYPE",
+ "K_NAME", "K_CLASS", "K_VOICE", "K_PAGETO", "K_LM", "K_LP", "K_ISCAN",
+ "K_PSCAN", "K_DISCOVTO", "K_PASSKEY", "K_YES", "K_NO", "WORD", "PATH",
+ "STRING", "LIST", "HCI", "BDADDR", "ID", "NUM", "'{'", "'}'", "';'",
+ "$accept", "config", "statement", "device", "hcid_options", "hcid_opts",
+ "hcid_opt", "sec_mode", "pair_mode", "off_mode", "dev_id",
+ "device_options", "device_opts", "device_opt", "dev_name", "hci",
+ "bdaddr", "pkt_type", "link_mode", "link_policy", "bool", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 123, 125, 59
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 34, 35, 35, 36, 36, 36, 36, 37, 37,
+ 37, 38, 39, 39, 39, 39, 40, 40, 40, 40,
+ 40, 40, 40, 41, 41, 42, 43, 44, 45, 46,
+ 46, 46, 46, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 48, 48, 49, 50, 51, 51,
+ 52, 52, 53, 53, 54, 54
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 2, 2, 2, 1, 1, 1, 2,
+ 2, 3, 0, 2, 2, 3, 2, 2, 2, 2,
+ 2, 2, 1, 1, 1, 1, 1, 1, 3, 0,
+ 2, 2, 3, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 7, 0, 8, 6, 0, 2, 0, 0, 4,
+ 46, 47, 9, 10, 1, 3, 0, 5, 0, 0,
+ 0, 0, 0, 0, 0, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 43,
+ 0, 0, 14, 54, 55, 16, 24, 23, 17, 25,
+ 18, 26, 19, 27, 20, 21, 11, 0, 13, 31,
+ 48, 49, 33, 44, 45, 36, 37, 38, 39, 50,
+ 51, 34, 52, 53, 35, 41, 42, 40, 28, 0,
+ 30, 15, 32
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 5, 6, 7, 9, 26, 27, 48, 50, 52,
+ 54, 17, 40, 41, 65, 12, 13, 62, 71, 74,
+ 45
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -23
+static const yytype_int8 yypact[] =
+{
+ 51, -23, -2, -7, -23, 39, -23, 1, 18, -23,
+ -23, -23, -23, -23, -23, -23, -1, -23, 16, -14,
+ 22, 30, 33, 29, 32, -23, 28, 26, 40, -22,
+ 5, 31, 45, 47, -21, -20, -14, -14, 48, -23,
+ 53, 46, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23, 49, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23, -23, -23, 50,
+ -23, -23, -23
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -23, -23, 75, -23, -23, -23, 55, -23, -23, -23,
+ -23, -23, -23, 44, -23, -23, -23, -23, -23, -23,
+ 10
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -30
+static const yytype_int8 yytable[] =
+{
+ 28, 60, 69, 72, 61, 70, 73, 43, 44, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 18,
+ 10, 11, 39, 19, 20, 21, 22, 23, 63, 8,
+ 64, -29, 16, 19, 20, 21, 22, 23, 24, 14,
+ 1, 25, 2, 3, 46, 47, 75, 76, 24, 42,
+ -12, 25, 1, 49, 2, 3, 51, 55, 53, 58,
+ 56, 66, 4, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 59, 4, 67, 39, 68, 77, 80,
+ 15, 57, 81, 82, 79, 78
+};
+
+static const yytype_uint8 yycheck[] =
+{
+ 1, 23, 23, 23, 26, 26, 26, 21, 22, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 1,
+ 27, 28, 23, 5, 6, 7, 8, 9, 23, 31,
+ 25, 32, 31, 5, 6, 7, 8, 9, 20, 0,
+ 1, 23, 3, 4, 22, 23, 36, 37, 20, 33,
+ 32, 23, 1, 23, 3, 4, 23, 25, 29, 33,
+ 32, 30, 23, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 33, 23, 30, 23, 30, 30, 33,
+ 5, 26, 33, 33, 40, 32
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 1, 3, 4, 23, 35, 36, 37, 31, 38,
+ 27, 28, 49, 50, 0, 36, 31, 45, 1, 5,
+ 6, 7, 8, 9, 20, 23, 39, 40, 1, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 23,
+ 46, 47, 33, 21, 22, 54, 22, 23, 41, 23,
+ 42, 23, 43, 29, 44, 25, 32, 40, 33, 33,
+ 23, 26, 51, 23, 25, 48, 30, 30, 30, 23,
+ 26, 52, 23, 26, 53, 54, 54, 30, 32, 47,
+ 33, 33, 33
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 6:
+#line 83 "parser.y"
+ {
+ cfg_error("Invalid statement '%s'", (yyvsp[(1) - (1)].str));
+ }
+ break;
+
+ case 7:
+#line 87 "parser.y"
+ {
+ yyclearin; yyerrok;
+ }
+ break;
+
+ case 8:
+#line 93 "parser.y"
+ {
+ parser_device = &default_device;
+ }
+ break;
+
+ case 9:
+#line 97 "parser.y"
+ {
+ parser_device = alloc_device_opts((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 10:
+#line 101 "parser.y"
+ {
+ parser_device = alloc_device_opts((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 16:
+#line 109 "parser.y"
+ {
+ hcid.auto_init = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 17:
+#line 113 "parser.y"
+ {
+ hcid.security = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 18:
+#line 117 "parser.y"
+ {
+ hcid.pairing = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 19:
+#line 121 "parser.y"
+ {
+ hcid.offmode = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 20:
+#line 125 "parser.y"
+ {
+ strncpy((char *) hcid.deviceid, (yyvsp[(2) - (2)].str), 15);
+ }
+ break;
+
+ case 21:
+#line 129 "parser.y"
+ {
+ strncpy((char *) hcid.pin_code, (yyvsp[(2) - (2)].str), 16);
+ hcid.pin_len = strlen((yyvsp[(2) - (2)].str));
+ if (hcid.pin_len > 16)
+ hcid.pin_len = 16;
+ }
+ break;
+
+ case 22:
+#line 137 "parser.y"
+ {
+ cfg_error("Unknown option '%s'", (yyvsp[(1) - (1)].str));
+ }
+ break;
+
+ case 23:
+#line 143 "parser.y"
+ {
+ int opt = find_keyword(sec_param, (yyvsp[(1) - (1)].str));
+ if (opt < 0) {
+ cfg_error("Unknown security mode '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = 0;
+ } else
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 24:
+#line 152 "parser.y"
+ {
+ (yyval.num) = HCID_SEC_NONE;
+ }
+ break;
+
+ case 25:
+#line 158 "parser.y"
+ {
+ int opt = find_keyword(pair_param, (yyvsp[(1) - (1)].str));
+ if (opt < 0) {
+ cfg_error("Unknown pairing mode '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = 0;
+ } else
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 26:
+#line 169 "parser.y"
+ {
+ int opt = find_keyword(off_param, (yyvsp[(1) - (1)].str));
+ if (opt < 0) {
+ cfg_error("Unknown off mode '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = 0;
+ } else
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 27:
+#line 180 "parser.y"
+ {
+ }
+ break;
+
+ case 33:
+#line 187 "parser.y"
+ {
+ parser_device->flags |= (1 << HCID_SET_PTYPE);
+ parser_device->pkt_type = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 34:
+#line 192 "parser.y"
+ {
+ parser_device->flags |= (1 << HCID_SET_LM);
+ parser_device->link_mode = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 35:
+#line 197 "parser.y"
+ {
+ parser_device->flags |= (1 << HCID_SET_LP);
+ parser_device->link_policy = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 36:
+#line 202 "parser.y"
+ {
+ if (parser_device->name)
+ g_free(parser_device->name);
+ parser_device->flags |= (1 << HCID_SET_NAME);
+ parser_device->name = g_strdup((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 37:
+#line 209 "parser.y"
+ {
+ parser_device->flags |= (1 << HCID_SET_CLASS);
+ parser_device->class = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 38:
+#line 214 "parser.y"
+ {
+ parser_device->flags |= (1 << HCID_SET_VOICE);
+ parser_device->voice = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 39:
+#line 219 "parser.y"
+ {
+ parser_device->flags |= (1 << HCID_SET_PAGETO);
+ parser_device->pageto = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 40:
+#line 224 "parser.y"
+ {
+ parser_device->flags |= (1 << HCID_SET_DISCOVTO);
+ parser_device->discovto = (yyvsp[(2) - (2)].num);
+ }
+ break;
+
+ case 41:
+#line 229 "parser.y"
+ {
+ if ((yyvsp[(2) - (2)].num))
+ parser_device->scan |= SCAN_INQUIRY;
+ else
+ parser_device->scan &= ~SCAN_INQUIRY;
+ }
+ break;
+
+ case 42:
+#line 236 "parser.y"
+ {
+ if ((yyvsp[(2) - (2)].num))
+ parser_device->scan |= SCAN_PAGE;
+ else
+ parser_device->scan &= ~SCAN_PAGE;
+ }
+ break;
+
+ case 43:
+#line 243 "parser.y"
+ {
+ cfg_error("Unknown option '%s'",(yyvsp[(1) - (1)].str));
+ YYABORT;
+ }
+ break;
+
+ case 44:
+#line 250 "parser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+ }
+ break;
+
+ case 45:
+#line 254 "parser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+ }
+ break;
+
+ case 46:
+#line 260 "parser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+ }
+ break;
+
+ case 47:
+#line 266 "parser.y"
+ {
+ (yyval.str) = (yyvsp[(1) - (1)].str);
+ }
+ break;
+
+ case 48:
+#line 272 "parser.y"
+ {
+ unsigned int opt;
+ if (!hci_strtoptype((yyvsp[(1) - (1)].str), &opt))
+ cfg_error("Unknown packet type '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 49:
+#line 279 "parser.y"
+ {
+ unsigned int opt;
+ if (!hci_strtoptype((yyvsp[(1) - (1)].str), &opt))
+ cfg_error("Unknown packet type '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 50:
+#line 288 "parser.y"
+ {
+ unsigned int opt;
+ if (!hci_strtolm((yyvsp[(1) - (1)].str), &opt))
+ cfg_error("Unknown link mode '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 51:
+#line 295 "parser.y"
+ {
+ unsigned int opt;
+ if (!hci_strtolm((yyvsp[(1) - (1)].str), &opt))
+ cfg_error("Unknown link mode '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 52:
+#line 304 "parser.y"
+ {
+ unsigned int opt;
+ if (!hci_strtolp((yyvsp[(1) - (1)].str), &opt))
+ cfg_error("Unknown link policy '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 53:
+#line 311 "parser.y"
+ {
+ unsigned int opt;
+ if (!hci_strtolp((yyvsp[(1) - (1)].str), &opt))
+ cfg_error("Unknown link policy '%s'", (yyvsp[(1) - (1)].str));
+ (yyval.num) = opt;
+ }
+ break;
+
+ case 54:
+#line 319 "parser.y"
+ { (yyval.num) = 1; }
+ break;
+
+ case 55:
+#line 319 "parser.y"
+ { (yyval.num) = 0; }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 1830 "parser.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 321 "parser.y"
+
+
+int yyerror(char *s)
+{
+ error("%s line %d", s, lineno);
+ return 0;
+}
+
+int cfg_error(const char *fmt, ...)
+{
+ char buf[255];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf,sizeof(buf),fmt,ap);
+ va_end(ap);
+
+ yyerror(buf);
+ return 0;
+}
+
+/*
+ * Read config file.
+ */
+int read_config(char *file)
+{
+ extern FILE *yyin;
+
+ if (!(yyin = fopen(file, "r"))) {
+ error("Can't open config file %s", file);
+ return -1;
+ }
+
+ lineno = 1;
+ yyparse();
+
+ fclose(yyin);
+
+ return 0;
+}
+
diff --git a/utils/hcid/parser.h b/utils/hcid/parser.h
new file mode 100644
index 00000000..433240ae
--- /dev/null
+++ b/utils/hcid/parser.h
@@ -0,0 +1,121 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ K_OPTIONS = 258,
+ K_DEVICE = 259,
+ K_AUTOINIT = 260,
+ K_SECURITY = 261,
+ K_PAIRING = 262,
+ K_OFFMODE = 263,
+ K_DEVICEID = 264,
+ K_PTYPE = 265,
+ K_NAME = 266,
+ K_CLASS = 267,
+ K_VOICE = 268,
+ K_PAGETO = 269,
+ K_LM = 270,
+ K_LP = 271,
+ K_ISCAN = 272,
+ K_PSCAN = 273,
+ K_DISCOVTO = 274,
+ K_PASSKEY = 275,
+ K_YES = 276,
+ K_NO = 277,
+ WORD = 278,
+ PATH = 279,
+ STRING = 280,
+ LIST = 281,
+ HCI = 282,
+ BDADDR = 283,
+ ID = 284,
+ NUM = 285
+ };
+#endif
+/* Tokens. */
+#define K_OPTIONS 258
+#define K_DEVICE 259
+#define K_AUTOINIT 260
+#define K_SECURITY 261
+#define K_PAIRING 262
+#define K_OFFMODE 263
+#define K_DEVICEID 264
+#define K_PTYPE 265
+#define K_NAME 266
+#define K_CLASS 267
+#define K_VOICE 268
+#define K_PAGETO 269
+#define K_LM 270
+#define K_LP 271
+#define K_ISCAN 272
+#define K_PSCAN 273
+#define K_DISCOVTO 274
+#define K_PASSKEY 275
+#define K_YES 276
+#define K_NO 277
+#define WORD 278
+#define PATH 279
+#define STRING 280
+#define LIST 281
+#define HCI 282
+#define BDADDR 283
+#define ID 284
+#define NUM 285
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 59 "parser.y"
+{
+ char *str;
+ long num;
+}
+/* Line 1489 of yacc.c. */
+#line 114 "parser.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/utils/hcid/parser.y b/utils/hcid/parser.y
new file mode 100644
index 00000000..c8b9a12d
--- /dev/null
+++ b/utils/hcid/parser.y
@@ -0,0 +1,360 @@
+%{
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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 <stdarg.h>
+
+#include <sys/socket.h>
+#include <asm/types.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hcid.h"
+#include "kword.h"
+
+int cfg_error(const char *fmt, ...);
+
+int yyparse(void);
+int yylex(void);
+int yyerror(char *s);
+
+void yylex_destroy(void);
+
+%}
+
+%union {
+ char *str;
+ long num;
+}
+
+%token K_OPTIONS K_DEVICE
+%token K_AUTOINIT K_SECURITY K_PAIRING K_OFFMODE K_DEVICEID
+%token K_PTYPE K_NAME K_CLASS K_VOICE K_PAGETO K_LM K_LP K_ISCAN K_PSCAN K_DISCOVTO
+%token K_PASSKEY
+%token K_YES K_NO
+
+%token <str> WORD PATH STRING LIST HCI BDADDR ID
+%token <num> NUM
+
+%type <num> bool pkt_type link_mode link_policy sec_mode pair_mode off_mode
+%type <str> dev_name dev_id hci bdaddr
+
+%%
+config: statement | config statement;
+statement:
+ K_OPTIONS hcid_options
+
+ | device device_options
+
+ | WORD {
+ cfg_error("Invalid statement '%s'", $1);
+ }
+
+ | error {
+ yyclearin; yyerrok;
+ }
+ ;
+
+device:
+ K_DEVICE {
+ parser_device = &default_device;
+ }
+
+ | K_DEVICE hci {
+ parser_device = alloc_device_opts($2);
+ }
+
+ | K_DEVICE bdaddr {
+ parser_device = alloc_device_opts($2);
+ }
+ ;
+
+hcid_options: '{' hcid_opts '}';
+hcid_opts: | hcid_opt ';' | error ';' | hcid_opts hcid_opt ';';
+hcid_opt:
+ K_AUTOINIT bool {
+ hcid.auto_init = $2;
+ }
+
+ | K_SECURITY sec_mode {
+ hcid.security = $2;
+ }
+
+ | K_PAIRING pair_mode {
+ hcid.pairing = $2;
+ }
+
+ | K_OFFMODE off_mode {
+ hcid.offmode = $2;
+ }
+
+ | K_DEVICEID dev_id {
+ strncpy((char *) hcid.deviceid, $2, 15);
+ }
+
+ | K_PASSKEY STRING {
+ strncpy((char *) hcid.pin_code, $2, 16);
+ hcid.pin_len = strlen($2);
+ if (hcid.pin_len > 16)
+ hcid.pin_len = 16;
+ }
+
+
+ | WORD {
+ cfg_error("Unknown option '%s'", $1);
+ }
+ ;
+
+sec_mode:
+ WORD {
+ int opt = find_keyword(sec_param, $1);
+ if (opt < 0) {
+ cfg_error("Unknown security mode '%s'", $1);
+ $$ = 0;
+ } else
+ $$ = opt;
+ }
+
+ | K_NO {
+ $$ = HCID_SEC_NONE;
+ }
+ ;
+
+pair_mode:
+ WORD {
+ int opt = find_keyword(pair_param, $1);
+ if (opt < 0) {
+ cfg_error("Unknown pairing mode '%s'", $1);
+ $$ = 0;
+ } else
+ $$ = opt;
+ }
+ ;
+
+off_mode:
+ WORD {
+ int opt = find_keyword(off_param, $1);
+ if (opt < 0) {
+ cfg_error("Unknown off mode '%s'", $1);
+ $$ = 0;
+ } else
+ $$ = opt;
+ }
+ ;
+
+dev_id:
+ ID {
+ }
+ ;
+
+device_options: '{' device_opts '}';
+device_opts: | device_opt ';' | error ';' | device_opts device_opt ';';
+device_opt:
+ K_PTYPE pkt_type {
+ parser_device->flags |= (1 << HCID_SET_PTYPE);
+ parser_device->pkt_type = $2;
+ }
+
+ | K_LM link_mode {
+ parser_device->flags |= (1 << HCID_SET_LM);
+ parser_device->link_mode = $2;
+ }
+
+ | K_LP link_policy {
+ parser_device->flags |= (1 << HCID_SET_LP);
+ parser_device->link_policy = $2;
+ }
+
+ | K_NAME dev_name {
+ if (parser_device->name)
+ g_free(parser_device->name);
+ parser_device->flags |= (1 << HCID_SET_NAME);
+ parser_device->name = g_strdup($2);
+ }
+
+ | K_CLASS NUM {
+ parser_device->flags |= (1 << HCID_SET_CLASS);
+ parser_device->class = $2;
+ }
+
+ | K_VOICE NUM {
+ parser_device->flags |= (1 << HCID_SET_VOICE);
+ parser_device->voice = $2;
+ }
+
+ | K_PAGETO NUM {
+ parser_device->flags |= (1 << HCID_SET_PAGETO);
+ parser_device->pageto = $2;
+ }
+
+ | K_DISCOVTO NUM {
+ parser_device->flags |= (1 << HCID_SET_DISCOVTO);
+ parser_device->discovto = $2;
+ }
+
+ | K_ISCAN bool {
+ if ($2)
+ parser_device->scan |= SCAN_INQUIRY;
+ else
+ parser_device->scan &= ~SCAN_INQUIRY;
+ }
+
+ | K_PSCAN bool {
+ if ($2)
+ parser_device->scan |= SCAN_PAGE;
+ else
+ parser_device->scan &= ~SCAN_PAGE;
+ }
+
+ | WORD {
+ cfg_error("Unknown option '%s'",$1);
+ YYABORT;
+ }
+ ;
+
+dev_name:
+ WORD {
+ $$ = $1;
+ }
+
+ | STRING {
+ $$ = $1;
+ }
+ ;
+
+hci:
+ HCI {
+ $$ = $1;
+ }
+ ;
+
+bdaddr:
+ BDADDR {
+ $$ = $1;
+ }
+ ;
+
+pkt_type:
+ WORD {
+ unsigned int opt;
+ if (!hci_strtoptype($1, &opt))
+ cfg_error("Unknown packet type '%s'", $1);
+ $$ = opt;
+ }
+
+ | LIST {
+ unsigned int opt;
+ if (!hci_strtoptype($1, &opt))
+ cfg_error("Unknown packet type '%s'", $1);
+ $$ = opt;
+ }
+ ;
+
+link_mode:
+ WORD {
+ unsigned int opt;
+ if (!hci_strtolm($1, &opt))
+ cfg_error("Unknown link mode '%s'", $1);
+ $$ = opt;
+ }
+
+ | LIST {
+ unsigned int opt;
+ if (!hci_strtolm($1, &opt))
+ cfg_error("Unknown link mode '%s'", $1);
+ $$ = opt;
+ }
+ ;
+
+link_policy:
+ WORD {
+ unsigned int opt;
+ if (!hci_strtolp($1, &opt))
+ cfg_error("Unknown link policy '%s'", $1);
+ $$ = opt;
+ }
+
+ | LIST {
+ unsigned int opt;
+ if (!hci_strtolp($1, &opt))
+ cfg_error("Unknown link policy '%s'", $1);
+ $$ = opt;
+ }
+ ;
+
+bool: K_YES { $$ = 1; } | K_NO { $$ = 0; };
+
+%%
+
+int yyerror(char *s)
+{
+ error("%s line %d", s, lineno);
+ return 0;
+}
+
+int cfg_error(const char *fmt, ...)
+{
+ char buf[255];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf,sizeof(buf),fmt,ap);
+ va_end(ap);
+
+ yyerror(buf);
+ return 0;
+}
+
+/*
+ * Read config file.
+ */
+int read_config(char *file)
+{
+ extern FILE *yyin;
+
+ if (!(yyin = fopen(file, "r"))) {
+ error("Can't open config file %s", file);
+ return -1;
+ }
+
+ lineno = 1;
+ yyparse();
+
+ fclose(yyin);
+
+ return 0;
+}
diff --git a/utils/hcid/plugin.c b/utils/hcid/plugin.c
new file mode 100644
index 00000000..41c55155
--- /dev/null
+++ b/utils/hcid/plugin.c
@@ -0,0 +1,185 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 <gmodule.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "logging.h"
+
+#include "plugin.h"
+
+static GSList *plugins = NULL;
+
+struct bluetooth_plugin {
+ GModule *module;
+ struct bluetooth_plugin_desc *desc;
+};
+
+static gboolean add_plugin(GModule *module, struct bluetooth_plugin_desc *desc)
+{
+ struct bluetooth_plugin *plugin;
+
+ if (desc->init() < 0)
+ return FALSE;
+
+ plugin = g_try_new0(struct bluetooth_plugin, 1);
+ if (plugin == NULL)
+ return FALSE;
+
+ plugin->module = module;
+ plugin->desc = desc;
+
+ plugins = g_slist_append(plugins, plugin);
+
+ return TRUE;
+}
+
+static gboolean is_disabled(const char *name, char **list)
+{
+ int i;
+
+ for (i = 0; list[i] != NULL; i++) {
+ char *str;
+ gboolean equal;
+
+ str = g_strdup_printf("lib%s.so", list[i]);
+
+ equal = g_str_equal(str, name);
+
+ g_free(str);
+
+ if (equal)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean plugin_init(GKeyFile *config)
+{
+ GDir *dir;
+ const gchar *file;
+ gchar **disabled;
+
+ if (config)
+ disabled = g_key_file_get_string_list(config, "General",
+ "DisablePlugins",
+ NULL, NULL);
+ else
+ disabled = NULL;
+
+ debug("Loading plugins %s", PLUGINDIR);
+
+ dir = g_dir_open(PLUGINDIR, 0, NULL);
+ if (!dir)
+ return FALSE;
+
+ while ((file = g_dir_read_name(dir)) != NULL) {
+ GModule *module;
+ struct bluetooth_plugin_desc *desc;
+ gchar *filename;
+ struct stat st;
+
+ if (g_str_has_prefix(file, "lib") == TRUE ||
+ g_str_has_suffix(file, ".so") == FALSE)
+ continue;
+
+ if (disabled && is_disabled(file, disabled))
+ continue;
+
+ filename = g_build_filename(PLUGINDIR, file, NULL);
+
+ if (stat(filename, &st) < 0) {
+ error("Can't load plugin %s: %s (%d)", filename,
+ strerror(errno), errno);
+ g_free(filename);
+ continue;
+ }
+
+ module = g_module_open(filename, G_MODULE_BIND_LOCAL);
+ if (module == NULL) {
+ error("Can't load plugin: %s", g_module_error());
+ g_free(filename);
+ continue;
+ }
+
+ g_free(filename);
+
+ debug("%s", g_module_name(module));
+
+ if (g_module_symbol(module, "bluetooth_plugin_desc",
+ (gpointer) &desc) == FALSE) {
+ error("Can't load plugin description");
+ g_module_close(module);
+ continue;
+ }
+
+ if (desc == NULL || desc->init == NULL) {
+ g_module_close(module);
+ continue;
+ }
+
+ if (add_plugin(module, desc) == FALSE) {
+ error("Can't init plugin %s", g_module_name(module));
+ g_module_close(module);
+ }
+ }
+
+ g_dir_close(dir);
+
+ g_strfreev(disabled);
+
+ return TRUE;
+}
+
+void plugin_cleanup(void)
+{
+ GSList *list;
+
+ debug("Cleanup plugins");
+
+ for (list = plugins; list; list = list->next) {
+ struct bluetooth_plugin *plugin = list->data;
+
+ debug("%s", g_module_name(plugin->module));
+
+ if (plugin->desc->exit)
+ plugin->desc->exit();
+
+ g_module_close(plugin->module);
+
+ g_free(plugin);
+ }
+
+ g_slist_free(plugins);
+}
diff --git a/utils/hcid/plugin.h b/utils/hcid/plugin.h
new file mode 100644
index 00000000..9248aab6
--- /dev/null
+++ b/utils/hcid/plugin.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct bluetooth_plugin_desc {
+ const char *name;
+ int (*init) (void);
+ void (*exit) (void);
+};
+
+#define BLUETOOTH_PLUGIN_DEFINE(name,init,exit) \
+ struct bluetooth_plugin_desc bluetooth_plugin_desc = { \
+ name, init, exit \
+ };
diff --git a/utils/hcid/security.c b/utils/hcid/security.c
new file mode 100644
index 00000000..0bfbcbec
--- /dev/null
+++ b/utils/hcid/security.c
@@ -0,0 +1,1037 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include "hcid.h"
+#include "textfile.h"
+#include "adapter.h"
+#include "dbus-hci.h"
+
+struct g_io_info {
+ GIOChannel *channel;
+ int watch_id;
+ int pin_length;
+};
+
+static struct g_io_info io_data[HCI_MAX_DEV];
+
+static int pairing = HCID_PAIRING_MULTI;
+
+static GSList *hci_req_queue = NULL;
+
+struct hci_req_data *hci_req_data_new(int dev_id, const bdaddr_t *dba, uint16_t ogf, uint16_t ocf, int event, const void *cparam, int clen)
+{
+ struct hci_req_data *data;
+
+ data = g_new0(struct hci_req_data, 1);
+
+ data->cparam = g_malloc(clen);
+ memcpy(data->cparam, cparam, clen);
+
+ bacpy(&data->dba, dba);
+
+ data->dev_id = dev_id;
+ data->status = REQ_PENDING;
+ data->ogf = ogf;
+ data->ocf = ocf;
+ data->event = event;
+ data->clen = clen;
+
+ return data;
+}
+
+static int hci_req_find_by_devid(const void *data, const void *user_data)
+{
+ const struct hci_req_data *req = data;
+ const int *dev_id = user_data;
+
+ return (*dev_id - req->dev_id);
+}
+
+static void hci_req_queue_process(int dev_id)
+{
+ int dd, ret_val;
+
+ /* send the next pending cmd */
+ dd = hci_open_dev(dev_id);
+ do {
+ struct hci_req_data *data;
+ GSList *l = g_slist_find_custom(hci_req_queue, &dev_id, hci_req_find_by_devid);
+
+ if (!l)
+ break;
+
+ data = l->data;
+ data->status = REQ_SENT;
+
+ 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);
+ g_free(data);
+ }
+
+ } while(ret_val < 0);
+
+ hci_close_dev(dd);
+}
+
+void hci_req_queue_append(struct hci_req_data *data)
+{
+ 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);
+ match = l->data;
+
+ if (match->status == REQ_SENT)
+ return;
+
+ hci_req_queue_process(data->dev_id);
+}
+
+void hci_req_queue_remove(int dev_id, bdaddr_t *dba)
+{
+ GSList *cur, *next;
+ struct hci_req_data *req;
+
+ for (cur = hci_req_queue; cur != NULL; cur = next) {
+ req = cur->data;
+ next = cur->next;
+ if ((req->dev_id != dev_id) || (bacmp(&req->dba, dba)))
+ continue;
+
+ hci_req_queue = g_slist_remove(hci_req_queue, req);
+ g_free(req->cparam);
+ g_free(req);
+ }
+}
+
+static void check_pending_hci_req(int dev_id, int event)
+{
+ struct hci_req_data *data;
+ GSList *l;
+
+ if (!hci_req_queue)
+ return;
+
+ /* find the first element(pending)*/
+ l = g_slist_find_custom(hci_req_queue, &dev_id, hci_req_find_by_devid);
+
+ if (!l)
+ return;
+
+ data = l->data;
+
+ /* skip if there is pending confirmation */
+ if (data->status == REQ_SENT) {
+ if (data->event != event)
+ return;
+
+ /* remove the confirmed cmd */
+ hci_req_queue = g_slist_remove(hci_req_queue, data);
+ g_free(data->cparam);
+ g_free(data);
+ }
+
+ hci_req_queue_process(dev_id);
+}
+
+static int get_handle(int dev, bdaddr_t *sba, bdaddr_t *dba, uint16_t *handle)
+{
+ struct hci_conn_list_req *cl;
+ struct hci_conn_info *ci;
+ char addr[18];
+ int i;
+
+ cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl));
+
+ ba2str(sba, addr);
+ cl->dev_id = hci_devid(addr);
+ cl->conn_num = 10;
+ ci = cl->conn_info;
+
+ if (ioctl(dev, HCIGETCONNLIST, (void *) cl) < 0) {
+ g_free(cl);
+ return -EIO;
+ }
+
+ for (i = 0; i < cl->conn_num; i++, ci++) {
+ if (bacmp(&ci->bdaddr, dba) == 0) {
+ *handle = ci->handle;
+ g_free(cl);
+ return 0;
+ }
+ }
+
+ g_free(cl);
+
+ return -ENOENT;
+}
+
+static inline int get_bdaddr(int dev, bdaddr_t *sba, uint16_t handle, bdaddr_t *dba)
+{
+ struct hci_conn_list_req *cl;
+ struct hci_conn_info *ci;
+ char addr[18];
+ int i;
+
+ cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl));
+
+ ba2str(sba, addr);
+ cl->dev_id = hci_devid(addr);
+ cl->conn_num = 10;
+ ci = cl->conn_info;
+
+ if (ioctl(dev, HCIGETCONNLIST, (void *) cl) < 0) {
+ g_free(cl);
+ return -EIO;
+ }
+
+ for (i = 0; i < cl->conn_num; i++, ci++)
+ if (ci->handle == handle) {
+ bacpy(dba, &ci->bdaddr);
+ g_free(cl);
+ return 0;
+ }
+
+ g_free(cl);
+
+ return -ENOENT;
+}
+
+static inline void update_lastseen(bdaddr_t *sba, bdaddr_t *dba)
+{
+ time_t t;
+ struct tm *tm;
+
+ t = time(NULL);
+ tm = gmtime(&t);
+
+ write_lastseen_info(sba, dba, tm);
+}
+
+static inline void update_lastused(bdaddr_t *sba, bdaddr_t *dba)
+{
+ time_t t;
+ struct tm *tm;
+
+ t = time(NULL);
+ tm = gmtime(&t);
+
+ write_lastused_info(sba, dba, tm);
+}
+
+/* Link Key handling */
+
+static void link_key_request(int dev, bdaddr_t *sba, bdaddr_t *dba)
+{
+ struct hci_auth_info_req req;
+ unsigned char key[16];
+ char sa[18], da[18];
+ uint8_t type;
+ int err;
+
+ ba2str(sba, sa); ba2str(dba, da);
+ info("link_key_request (sba=%s, dba=%s)", sa, da);
+
+ memset(&req, 0, sizeof(req));
+ bacpy(&req.bdaddr, dba);
+
+ err = ioctl(dev, HCIGETAUTHINFO, (unsigned long) &req);
+ if (err < 0 && errno != EINVAL)
+ debug("HCIGETAUTHINFO failed %s (%d)",
+ strerror(errno), errno);
+ else
+ req.type = 0x00;
+
+ debug("kernel auth requirements = 0x%02x", req.type);
+
+ err = read_link_key(sba, dba, key, &type);
+ if (err < 0) {
+ /* Link key not found */
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, 6, dba);
+ } else {
+ /* Link key found */
+ link_key_reply_cp lr;
+ memcpy(lr.link_key, key, 16);
+ bacpy(&lr.bdaddr, dba);
+
+ debug("stored link key type = 0x%02x", type);
+
+ if ((type == 0x03 || type == 0x04) && (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,
+ LINK_KEY_REPLY_CP_SIZE, &lr);
+ }
+}
+
+static void link_key_notify(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_link_key_notify *evt = ptr;
+ bdaddr_t *dba = &evt->bdaddr;
+ char sa[18], da[18];
+ int dev_id, err;
+
+ ba2str(sba, sa); ba2str(dba, da);
+ info("link_key_notify (sba=%s, dba=%s)", sa, da);
+
+ dev_id = hci_devid(sa);
+
+ err = write_link_key(sba, dba, evt->link_key, evt->key_type,
+ io_data[dev_id].pin_length);
+ if (err < 0) {
+ uint16_t handle;
+
+ error("write_link_key: %s (%d)", strerror(-err), -err);
+
+ hcid_dbus_bonding_process_complete(sba, dba, HCI_MEMORY_FULL);
+
+ if (get_handle(dev, sba, dba, &handle) == 0) {
+ disconnect_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = htobs(handle);
+ cp.reason = HCI_OE_LOW_RESOURCES;
+
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_DISCONNECT,
+ DISCONNECT_CP_SIZE, &cp);
+ }
+ } else
+ hcid_dbus_bonding_process_complete(sba, dba, 0);
+
+ io_data[dev_id].pin_length = -1;
+}
+
+static void return_link_keys(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_return_link_keys *evt = ptr;
+ uint8_t num = evt->num_keys;
+ unsigned char key[16];
+ char sa[18], da[18];
+ bdaddr_t dba;
+ int i;
+
+ ba2str(sba, sa);
+ ptr++;
+
+ for (i = 0; i < num; i++) {
+ bacpy(&dba, ptr); ba2str(&dba, da);
+ memcpy(key, ptr + 6, 16);
+
+ info("return_link_keys (sba=%s, dba=%s)", sa, da);
+
+ ptr += 22;
+ }
+}
+
+/* Simple Pairing handling */
+
+static void user_confirm_request(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_user_confirm_request *req = ptr;
+
+ if (hcid_dbus_user_confirm(sba, &req->bdaddr,
+ btohl(req->passkey)) < 0)
+ hci_send_cmd(dev, OGF_LINK_CTL,
+ OCF_USER_CONFIRM_NEG_REPLY, 6, ptr);
+}
+
+static void user_passkey_request(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_user_passkey_request *req = ptr;
+
+ if (hcid_dbus_user_passkey(sba, &req->bdaddr) < 0)
+ hci_send_cmd(dev, OGF_LINK_CTL,
+ OCF_USER_PASSKEY_NEG_REPLY, 6, ptr);
+}
+
+static void user_passkey_notify(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_user_passkey_notify *req = ptr;
+
+ hcid_dbus_user_notify(sba, &req->bdaddr, btohl(req->passkey));
+}
+
+static void remote_oob_data_request(int dev, bdaddr_t *sba, void *ptr)
+{
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, ptr);
+}
+
+static void io_capa_request(int dev, bdaddr_t *sba, bdaddr_t *dba)
+{
+ char sa[18], da[18];
+ uint8_t cap, auth;
+
+ ba2str(sba, sa); ba2str(dba, da);
+ info("io_capa_request (sba=%s, dba=%s)", sa, da);
+
+ if (hcid_dbus_get_io_cap(sba, dba, &cap, &auth) < 0) {
+ io_capability_neg_reply_cp cp;
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, dba);
+ cp.reason = HCI_PAIRING_NOT_ALLOWED;
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_NEG_REPLY,
+ IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);
+ } else {
+ io_capability_reply_cp cp;
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, dba);
+ cp.capability = cap;
+ cp.oob_data = 0x00;
+ cp.authentication = auth;
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
+ IO_CAPABILITY_REPLY_CP_SIZE, &cp);
+ }
+}
+
+static void io_capa_response(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_io_capability_response *evt = ptr;
+ char sa[18], da[18];
+
+ ba2str(sba, sa); ba2str(&evt->bdaddr, da);
+ info("io_capa_response (sba=%s, dba=%s)", sa, da);
+
+ hcid_dbus_set_io_cap(sba, &evt->bdaddr,
+ evt->capability, evt->authentication);
+}
+
+/* PIN code handling */
+
+void set_pin_length(bdaddr_t *sba, int length)
+{
+ char addr[18];
+ int dev_id;
+
+ ba2str(sba, addr);
+ dev_id = hci_devid(addr);
+
+ io_data[dev_id].pin_length = length;
+}
+
+static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba)
+{
+ pin_code_reply_cp pr;
+ struct hci_conn_info_req *cr;
+ struct hci_conn_info *ci;
+ unsigned char key[16];
+ char sa[18], da[18], pin[17];
+ int err, pinlen;
+
+ memset(&pr, 0, sizeof(pr));
+ bacpy(&pr.bdaddr, dba);
+
+ ba2str(sba, sa); ba2str(dba, da);
+ info("pin_code_request (sba=%s, dba=%s)", sa, da);
+
+ cr = g_malloc0(sizeof(*cr) + sizeof(*ci));
+
+ bacpy(&cr->bdaddr, dba);
+ cr->type = ACL_LINK;
+ if (ioctl(dev, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ error("Can't get conn info: %s (%d)", strerror(errno), errno);
+ goto reject;
+ }
+ ci = cr->conn_info;
+
+ memset(pin, 0, sizeof(pin));
+ pinlen = read_pin_code(sba, dba, pin);
+
+ if (pairing == HCID_PAIRING_ONCE) {
+ err = read_link_key(sba, dba, key, NULL);
+ if (!err) {
+ ba2str(dba, da);
+ error("PIN code request for already paired device %s", da);
+ goto reject;
+ }
+ } else if (pairing == HCID_PAIRING_NONE)
+ goto reject;
+
+ if (hcid.security == HCID_SEC_AUTO && !ci->out) {
+ set_pin_length(sba, hcid.pin_len);
+ memcpy(pr.pin_code, hcid.pin_code, hcid.pin_len);
+ pr.pin_len = hcid.pin_len;
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY,
+ PIN_CODE_REPLY_CP_SIZE, &pr);
+ } else {
+ if (pinlen > 0) {
+ set_pin_length(sba, pinlen);
+ memcpy(pr.pin_code, pin, pinlen);
+ pr.pin_len = pinlen;
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY,
+ PIN_CODE_REPLY_CP_SIZE, &pr);
+ } else {
+ /* Request PIN from passkey agent */
+ if (hcid_dbus_request_pin(dev, sba, ci) < 0)
+ goto reject;
+ }
+ }
+
+ g_free(cr);
+
+ return;
+
+reject:
+ g_free(cr);
+
+ hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba);
+}
+
+static inline void cmd_status(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_cmd_status *evt = ptr;
+ uint16_t opcode = btohs(evt->opcode);
+
+ if (evt->status)
+ return;
+
+ if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))
+ hcid_dbus_inquiry_start(sba);
+}
+
+static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_cmd_complete *evt = ptr;
+ uint16_t opcode = btohs(evt->opcode);
+ uint8_t status;
+
+ switch (opcode) {
+ case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY):
+ status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE);
+ hcid_dbus_periodic_inquiry_start(sba, status);
+ break;
+ case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY):
+ status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE);
+ hcid_dbus_periodic_inquiry_exit(sba, status);
+ break;
+ case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
+ hcid_dbus_inquiry_complete(sba);
+ break;
+ case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
+ hcid_dbus_setname_complete(sba);
+ break;
+ case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
+ 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);
+ break;
+ case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SIMPLE_PAIRING_MODE):
+ hcid_dbus_write_simple_pairing_mode_complete(sba);
+ break;
+ };
+}
+
+static inline void remote_name_information(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_remote_name_req_complete *evt = ptr;
+ bdaddr_t dba;
+ char name[249];
+
+ memset(name, 0, sizeof(name));
+ bacpy(&dba, &evt->bdaddr);
+
+ if (!evt->status) {
+ char *end;
+ memcpy(name, evt->name, 248);
+ /* It's ok to cast end between const and non-const since
+ * we know it points to inside of name which is non-const */
+ if (!g_utf8_validate(name, -1, (const char **) &end))
+ *end = '\0';
+ write_device_name(sba, &dba, name);
+ }
+
+ hcid_dbus_remote_name(sba, &dba, evt->status, name);
+}
+
+static inline void remote_version_information(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_read_remote_version_complete *evt = ptr;
+ bdaddr_t dba;
+
+ if (evt->status)
+ return;
+
+ if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0)
+ return;
+
+ write_version_info(sba, &dba, btohs(evt->manufacturer),
+ evt->lmp_ver, btohs(evt->lmp_subver));
+}
+
+static inline void inquiry_complete(int dev, bdaddr_t *sba, void *ptr)
+{
+ hcid_dbus_inquiry_complete(sba);
+}
+
+static inline void inquiry_result(int dev, bdaddr_t *sba, int plen, void *ptr)
+{
+ uint8_t num = *(uint8_t *) ptr++;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ inquiry_info *info = ptr;
+ uint32_t class = info->dev_class[0]
+ | (info->dev_class[1] << 8)
+ | (info->dev_class[2] << 16);
+
+ hcid_dbus_inquiry_result(sba, &info->bdaddr, class, 0, NULL);
+
+ update_lastseen(sba, &info->bdaddr);
+
+ ptr += INQUIRY_INFO_SIZE;
+ }
+}
+
+static inline void inquiry_result_with_rssi(int dev, bdaddr_t *sba, int plen, void *ptr)
+{
+ uint8_t num = *(uint8_t *) ptr++;
+ int i;
+
+ if (!num)
+ return;
+
+ if ((plen - 1) / num == INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE) {
+ for (i = 0; i < num; i++) {
+ inquiry_info_with_rssi_and_pscan_mode *info = ptr;
+ uint32_t class = info->dev_class[0]
+ | (info->dev_class[1] << 8)
+ | (info->dev_class[2] << 16);
+
+ hcid_dbus_inquiry_result(sba, &info->bdaddr,
+ class, info->rssi, NULL);
+
+ update_lastseen(sba, &info->bdaddr);
+
+ ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
+ }
+ } else {
+ for (i = 0; i < num; i++) {
+ inquiry_info_with_rssi *info = ptr;
+ uint32_t class = info->dev_class[0]
+ | (info->dev_class[1] << 8)
+ | (info->dev_class[2] << 16);
+
+ hcid_dbus_inquiry_result(sba, &info->bdaddr,
+ class, info->rssi, NULL);
+
+ update_lastseen(sba, &info->bdaddr);
+
+ ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
+ }
+ }
+}
+
+static inline void extended_inquiry_result(int dev, bdaddr_t *sba, int plen, void *ptr)
+{
+ uint8_t num = *(uint8_t *) ptr++;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ extended_inquiry_info *info = ptr;
+ uint32_t class = info->dev_class[0]
+ | (info->dev_class[1] << 8)
+ | (info->dev_class[2] << 16);
+
+ hcid_dbus_inquiry_result(sba, &info->bdaddr, class,
+ info->rssi, info->data);
+
+ update_lastseen(sba, &info->bdaddr);
+
+ ptr += EXTENDED_INQUIRY_INFO_SIZE;
+ }
+}
+
+static inline void remote_features_information(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_read_remote_features_complete *evt = ptr;
+ bdaddr_t dba;
+
+ if (evt->status)
+ return;
+
+ if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0)
+ return;
+
+ write_features_info(sba, &dba, evt->features);
+}
+
+static inline void conn_complete(int dev, int dev_id, bdaddr_t *sba, void *ptr)
+{
+ evt_conn_complete *evt = ptr;
+ char filename[PATH_MAX];
+ remote_name_req_cp cp_name;
+ struct hci_req_data *data;
+ char local_addr[18], peer_addr[18], *str;
+
+ if (evt->link_type != ACL_LINK)
+ return;
+
+ hcid_dbus_conn_complete(sba, evt->status, btohs(evt->handle),
+ &evt->bdaddr);
+
+ if (evt->status)
+ return;
+
+ update_lastused(sba, &evt->bdaddr);
+
+ /* Request remote name */
+ memset(&cp_name, 0, sizeof(cp_name));
+ bacpy(&cp_name.bdaddr, &evt->bdaddr);
+ 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,
+ &cp_name, REMOTE_NAME_REQ_CP_SIZE);
+
+ hci_req_queue_append(data);
+
+ /* check if the remote version needs be requested */
+ ba2str(sba, local_addr);
+ ba2str(&evt->bdaddr, peer_addr);
+
+ create_name(filename, sizeof(filename), STORAGEDIR, local_addr, "manufacturers");
+
+ str = textfile_get(filename, peer_addr);
+ if (!str) {
+ read_remote_version_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ 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,
+ &cp, READ_REMOTE_VERSION_CP_SIZE);
+
+ hci_req_queue_append(data);
+ } else
+ free(str);
+}
+
+static inline void disconn_complete(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_disconn_complete *evt = ptr;
+
+ hcid_dbus_disconn_complete(sba, evt->status, btohs(evt->handle),
+ evt->reason);
+}
+
+static inline void auth_complete(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_auth_complete *evt = ptr;
+ bdaddr_t dba;
+
+ if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0)
+ return;
+
+ if (evt->status)
+ hcid_dbus_bonding_process_complete(sba, &dba, evt->status);
+}
+
+static inline void conn_request(int dev, bdaddr_t *sba, void *ptr)
+{
+ evt_conn_request *evt = ptr;
+ uint32_t class = evt->dev_class[0] | (evt->dev_class[1] << 8)
+ | (evt->dev_class[2] << 16);
+
+ hcid_dbus_remote_class(sba, &evt->bdaddr, class);
+
+ write_remote_class(sba, &evt->bdaddr, class);
+}
+
+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;
+ int type, dev;
+ size_t len;
+ hci_event_hdr *eh;
+ GIOError err;
+
+ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_unref(chan);
+ return FALSE;
+ }
+
+ if ((err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len))) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+ g_io_channel_unref(chan);
+ return FALSE;
+ }
+
+ type = *ptr++;
+
+ if (type != HCI_EVENT_PKT)
+ return TRUE;
+
+ eh = (hci_event_hdr *) ptr;
+ ptr += HCI_EVENT_HDR_SIZE;
+
+ dev = g_io_channel_unix_get_fd(chan);
+
+ ioctl(dev, HCIGETDEVINFO, (void *) di);
+
+ if (hci_test_bit(HCI_RAW, &di->flags))
+ return TRUE;
+
+ switch (eh->evt) {
+ case EVT_CMD_STATUS:
+ cmd_status(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_CMD_COMPLETE:
+ cmd_complete(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_REMOTE_NAME_REQ_COMPLETE:
+ remote_name_information(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_READ_REMOTE_VERSION_COMPLETE:
+ remote_version_information(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_READ_REMOTE_FEATURES_COMPLETE:
+ remote_features_information(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_INQUIRY_COMPLETE:
+ inquiry_complete(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_INQUIRY_RESULT:
+ inquiry_result(dev, &di->bdaddr, eh->plen, ptr);
+ break;
+
+ case EVT_INQUIRY_RESULT_WITH_RSSI:
+ inquiry_result_with_rssi(dev, &di->bdaddr, eh->plen, ptr);
+ break;
+
+ case EVT_EXTENDED_INQUIRY_RESULT:
+ extended_inquiry_result(dev, &di->bdaddr, eh->plen, ptr);
+ break;
+
+ case EVT_CONN_COMPLETE:
+ conn_complete(dev, di->dev_id, &di->bdaddr, ptr);
+ break;
+
+ case EVT_DISCONN_COMPLETE:
+ disconn_complete(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_AUTH_COMPLETE:
+ auth_complete(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_CONN_REQUEST:
+ conn_request(dev, &di->bdaddr, ptr);
+ break;
+ }
+
+ /* Check for pending command request */
+ check_pending_hci_req(di->dev_id, eh->evt);
+
+ if (hci_test_bit(HCI_SECMGR, &di->flags))
+ return TRUE;
+
+ switch (eh->evt) {
+ case EVT_PIN_CODE_REQ:
+ pin_code_request(dev, &di->bdaddr, (bdaddr_t *) ptr);
+ break;
+
+ case EVT_LINK_KEY_REQ:
+ link_key_request(dev, &di->bdaddr, (bdaddr_t *) ptr);
+ break;
+
+ case EVT_LINK_KEY_NOTIFY:
+ link_key_notify(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_RETURN_LINK_KEYS:
+ return_link_keys(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_IO_CAPABILITY_REQUEST:
+ io_capa_request(dev, &di->bdaddr, (bdaddr_t *) ptr);
+ break;
+
+ case EVT_IO_CAPABILITY_RESPONSE:
+ io_capa_response(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_USER_CONFIRM_REQUEST:
+ user_confirm_request(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_USER_PASSKEY_REQUEST:
+ user_passkey_request(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_USER_PASSKEY_NOTIFY:
+ user_passkey_notify(dev, &di->bdaddr, ptr);
+ break;
+
+ case EVT_REMOTE_OOB_DATA_REQUEST:
+ remote_oob_data_request(dev, &di->bdaddr, ptr);
+ break;
+ }
+
+ return TRUE;
+}
+
+void start_security_manager(int hdev)
+{
+ GIOChannel *chan = io_data[hdev].channel;
+ struct hci_dev_info *di;
+ struct hci_filter flt;
+ read_stored_link_key_cp cp;
+ int dev;
+
+ if (chan)
+ return;
+
+ info("Starting security manager %d", hdev);
+
+ if ((dev = hci_open_dev(hdev)) < 0) {
+ error("Can't open device hci%d: %s (%d)",
+ hdev, strerror(errno), errno);
+ return;
+ }
+
+ /* Set filter */
+ hci_filter_clear(&flt);
+ hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
+ hci_filter_set_event(EVT_CMD_STATUS, &flt);
+ hci_filter_set_event(EVT_CMD_COMPLETE, &flt);
+ hci_filter_set_event(EVT_PIN_CODE_REQ, &flt);
+ hci_filter_set_event(EVT_LINK_KEY_REQ, &flt);
+ hci_filter_set_event(EVT_LINK_KEY_NOTIFY, &flt);
+ hci_filter_set_event(EVT_RETURN_LINK_KEYS, &flt);
+ hci_filter_set_event(EVT_IO_CAPABILITY_REQUEST, &flt);
+ hci_filter_set_event(EVT_IO_CAPABILITY_RESPONSE, &flt);
+ hci_filter_set_event(EVT_USER_CONFIRM_REQUEST, &flt);
+ hci_filter_set_event(EVT_USER_PASSKEY_REQUEST, &flt);
+ hci_filter_set_event(EVT_REMOTE_OOB_DATA_REQUEST, &flt);
+ hci_filter_set_event(EVT_USER_PASSKEY_NOTIFY, &flt);
+ hci_filter_set_event(EVT_KEYPRESS_NOTIFY, &flt);
+ hci_filter_set_event(EVT_SIMPLE_PAIRING_COMPLETE, &flt);
+ hci_filter_set_event(EVT_AUTH_COMPLETE, &flt);
+ hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt);
+ hci_filter_set_event(EVT_READ_REMOTE_VERSION_COMPLETE, &flt);
+ hci_filter_set_event(EVT_READ_REMOTE_FEATURES_COMPLETE, &flt);
+ hci_filter_set_event(EVT_REMOTE_HOST_FEATURES_NOTIFY, &flt);
+ hci_filter_set_event(EVT_INQUIRY_COMPLETE, &flt);
+ hci_filter_set_event(EVT_INQUIRY_RESULT, &flt);
+ hci_filter_set_event(EVT_INQUIRY_RESULT_WITH_RSSI, &flt);
+ hci_filter_set_event(EVT_EXTENDED_INQUIRY_RESULT, &flt);
+ hci_filter_set_event(EVT_CONN_REQUEST, &flt);
+ hci_filter_set_event(EVT_CONN_COMPLETE, &flt);
+ hci_filter_set_event(EVT_DISCONN_COMPLETE, &flt);
+ if (setsockopt(dev, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+ error("Can't set filter on hci%d: %s (%d)",
+ hdev, strerror(errno), errno);
+ close(dev);
+ return;
+ }
+
+ di = g_new(struct hci_dev_info, 1);
+ if (hci_devinfo(hdev, di) < 0) {
+ error("Can't get device info: %s (%d)",
+ strerror(errno), errno);
+ close(dev);
+ g_free(di);
+ return;
+ }
+
+ 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,
+ G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+ io_security_event, di, (GDestroyNotify) g_free);
+ io_data[hdev].channel = chan;
+ io_data[hdev].pin_length = -1;
+
+ if (hci_test_bit(HCI_RAW, &di->flags))
+ return;
+
+ bacpy(&cp.bdaddr, BDADDR_ANY);
+ cp.read_all = 1;
+
+ hci_send_cmd(dev, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,
+ READ_STORED_LINK_KEY_CP_SIZE, (void *) &cp);
+}
+
+void stop_security_manager(int hdev)
+{
+ GIOChannel *chan = io_data[hdev].channel;
+
+ if (!chan)
+ return;
+
+ info("Stopping security manager %d", hdev);
+
+ g_source_remove(io_data[hdev].watch_id);
+ g_io_channel_unref(io_data[hdev].channel);
+ io_data[hdev].watch_id = -1;
+ io_data[hdev].channel = NULL;
+ io_data[hdev].pin_length = -1;
+}
+
+void init_security_data(void)
+{
+ pairing = hcid.pairing;
+}
diff --git a/utils/hcid/server.c b/utils/hcid/server.c
new file mode 100644
index 00000000..da240112
--- /dev/null
+++ b/utils/hcid/server.c
@@ -0,0 +1,68 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 "server.h"
+
+static GSList *servers = NULL;
+
+int bt_register_server(struct bt_server *server)
+{
+ servers = g_slist_append(servers, server);
+
+ return 0;
+}
+
+void bt_unregister_server(struct bt_server *server)
+{
+ servers = g_slist_remove(servers, server);
+}
+
+void __probe_servers(const char *adapter)
+{
+ GSList *list;
+
+ for (list = servers; list; list = list->next) {
+ struct bt_server *server = list->data;
+
+ if (server->probe)
+ server->probe(adapter);
+ }
+}
+
+void __remove_servers(const char *adapter)
+{
+ GSList *list;
+
+ for (list = servers; list; list = list->next) {
+ struct bt_server *server = list->data;
+
+ if (server->remove)
+ server->remove(adapter);
+ }
+}
diff --git a/utils/hcid/server.h b/utils/hcid/server.h
new file mode 100644
index 00000000..f60ab88b
--- /dev/null
+++ b/utils/hcid/server.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct bt_server {
+ const char *uuid;
+ int (*probe) (const char *adapter);
+ void (*remove) (const char *adapter);
+};
+
+int bt_register_server(struct bt_server *server);
+void bt_unregister_server(struct bt_server *server);
diff --git a/utils/hcid/service-did.xml b/utils/hcid/service-did.xml
new file mode 100644
index 00000000..52eb68c0
--- /dev/null
+++ b/utils/hcid/service-did.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="0x1200"/>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0200">
+ <uint16 value="0x0102" name="id"/>
+ </attribute>
+
+ <attribute id="0x0201">
+ <uint16 value="0x0a12" name="vendor"/>
+ </attribute>
+
+ <attribute id="0x0202">
+ <uint16 value="0x4711" name="product"/>
+ </attribute>
+
+ <attribute id="0x0203">
+ <uint16 value="0x0000" name="version"/>
+ </attribute>
+
+ <attribute id="0x0204">
+ <boolean value="true"/>
+ </attribute>
+
+ <attribute id="0x0205">
+ <uint16 value="0x0002" name="source"/>
+ </attribute>
+</record>
diff --git a/utils/hcid/service-ftp.xml b/utils/hcid/service-ftp.xml
new file mode 100644
index 00000000..1bda8857
--- /dev/null
+++ b/utils/hcid/service-ftp.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="0x1106"/>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0004">
+ <sequence>
+ <sequence>
+ <uuid value="0x0100"/>
+ </sequence>
+ <sequence>
+ <uuid value="0x0003"/>
+ <uint8 value="23" name="channel"/>
+ </sequence>
+ <sequence>
+ <uuid value="0x0008"/>
+ </sequence>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0009">
+ <sequence>
+ <sequence>
+ <uuid value="0x1106"/>
+ <uint16 value="0x0100" name="version"/>
+ </sequence>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0100">
+ <text value="OBEX File Transfer" name="name"/>
+ </attribute>
+</record>
diff --git a/utils/hcid/service-opp.xml b/utils/hcid/service-opp.xml
new file mode 100644
index 00000000..351b4a41
--- /dev/null
+++ b/utils/hcid/service-opp.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="0x1105"/>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0004">
+ <sequence>
+ <sequence>
+ <uuid value="0x0100"/>
+ </sequence>
+ <sequence>
+ <uuid value="0x0003"/>
+ <uint8 value="23" name="channel"/>
+ </sequence>
+ <sequence>
+ <uuid value="0x0008"/>
+ </sequence>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0009">
+ <sequence>
+ <sequence>
+ <uuid value="0x1105"/>
+ <uint16 value="0x0100" name="version"/>
+ </sequence>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0100">
+ <text value="OBEX Object Push" name="name"/>
+ </attribute>
+
+ <attribute id="0x0303">
+ <sequence>
+ <uint8 value="0x01"/>
+ <uint8 value="0x01"/>
+ <uint8 value="0x02"/>
+ <uint8 value="0x03"/>
+ <uint8 value="0x04"/>
+ <uint8 value="0x05"/>
+ <uint8 value="0x06"/>
+ <uint8 value="0xff"/>
+ </sequence>
+ </attribute>
+</record>
diff --git a/utils/hcid/service-record.dtd b/utils/hcid/service-record.dtd
new file mode 100644
index 00000000..f53be5d0
--- /dev/null
+++ b/utils/hcid/service-record.dtd
@@ -0,0 +1,66 @@
+<!ELEMENT record (attribute)*>
+
+<!ELEMENT attribute (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|nil)+>
+<!ATTLIST attribute id CDATA #REQUIRED>
+
+<!ELEMENT sequence (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|uint128|int8|int16|int32|int64|int128|nil)+>
+
+<!ELEMENT alternate (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|uint128|int8|int16|int32|int64|int128|nil)+>
+
+<!ELEMENT text EMPTY>
+<!ATTLIST text value CDATA #REQUIRED>
+<!ATTLIST text name CDATA>
+<!ATTLIST text encoding (normal|hex) "normal">
+
+<!ELEMENT url EMPTY>
+<!ATTLIST url value CDATA #REQUIRED>
+<!ATTLIST url name CDATA>
+
+<!ELEMENT uuid EMPTY>
+<!ATTLIST uuid value CDATA #REQUIRED>
+
+<!ELEMENT boolean EMPTY>
+<!ATTLIST boolean value CDATA #REQUIRED>
+<!ATTLIST boolean name CDATA>
+
+<!ELEMENT uint8 EMPTY>
+<!ATTLIST uint8 value CDATA #REQUIRED>
+<!ATTLIST uint8 name CDATA>
+
+<!ELEMENT uint16 EMPTY>
+<!ATTLIST uint16 value CDATA #REQUIRED>
+<!ATTLIST uint16 name CDATA>
+
+<!ELEMENT uint32 EMPTY>
+<!ATTLIST uint32 value CDATA #REQUIRED>
+<!ATTLIST uint32 name CDATA>
+
+<!ELEMENT uint64 EMPTY>
+<!ATTLIST uint64 value CDATA #REQUIRED>
+<!ATTLIST uint64 name CDATA>
+
+<!ELEMENT uint128 EMPTY>
+<!ATTLIST uint128 value CDATA #REQUIRED>
+<!ATTLIST uint128 name CDATA>
+
+<!ELEMENT int8 EMPTY>
+<!ATTLIST int8 value CDATA #REQUIRED>
+<!ATTLIST int8 name CDATA>
+
+<!ELEMENT int16 EMPTY>
+<!ATTLIST int16 value CDATA #REQUIRED>
+<!ATTLIST int16 name CDATA>
+
+<!ELEMENT int32 EMPTY>
+<!ATTLIST int32 value CDATA #REQUIRED>
+<!ATTLIST int32 name CDATA>
+
+<!ELEMENT int64 EMPTY>
+<!ATTLIST int64 value CDATA #REQUIRED>
+<!ATTLIST int64 name CDATA>
+
+<!ELEMENT int128 EMPTY>
+<!ATTLIST int128 value CDATA #REQUIRED>
+<!ATTLIST int128 name CDATA>
+
+<!ELEMENT nil EMPTY>
diff --git a/utils/hcid/service-spp.xml b/utils/hcid/service-spp.xml
new file mode 100644
index 00000000..2b156c3f
--- /dev/null
+++ b/utils/hcid/service-spp.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<record>
+ <attribute id="0x0001">
+ <sequence>
+ <uuid value="0x1101"/>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0004">
+ <sequence>
+ <sequence>
+ <uuid value="0x0100"/>
+ </sequence>
+ <sequence>
+ <uuid value="0x0003"/>
+ <uint8 value="23" name="channel"/>
+ </sequence>
+ </sequence>
+ </attribute>
+
+ <attribute id="0x0100">
+ <text value="COM5" name="name"/>
+ </attribute>
+</record>
diff --git a/utils/hcid/simple-agent b/utils/hcid/simple-agent
new file mode 100755
index 00000000..0d3dc1f7
--- /dev/null
+++ b/utils/hcid/simple-agent
@@ -0,0 +1,112 @@
+#!/usr/bin/python
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+
+class Rejected(dbus.DBusException):
+ _dbus_error_name = "org.bluez.Error.Rejected"
+
+class Agent(dbus.service.Object):
+ exit_on_release = True
+
+ def set_exit_on_release(self, exit_on_release):
+ self.exit_on_release = exit_on_release
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="", out_signature="")
+ def Release(self):
+ print "Release"
+ if self.exit_on_release:
+ mainloop.quit()
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="os", out_signature="")
+ def Authorize(self, device, uuid):
+ print "Authorize (%s, %s)" % (device, uuid)
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="o", out_signature="s")
+ def RequestPinCode(self, device):
+ print "RequestPinCode (%s)" % (device)
+ return raw_input("Enter PIN Code: ")
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="o", out_signature="u")
+ def RequestPasskey(self, device):
+ print "RequestPasskey (%s)" % (device)
+ passkey = raw_input("Enter passkey: ")
+ return dbus.UInt32(passkey)
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="ou", out_signature="")
+ def DisplayPasskey(self, device, passkey):
+ print "DisplayPasskey (%s, %d)" % (device, passkey)
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="ou", out_signature="")
+ def RequestConfirmation(self, device, passkey):
+ print "RequestConfirmation (%s, %d)" % (device, passkey)
+ confirm = raw_input("Confirm passkey (yes/no): ")
+ if (confirm == "yes"):
+ return
+ raise Rejected("Passkey doesn't match")
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="s", out_signature="")
+ def ConfirmModeChange(self, mode):
+ print "ConfirmModeChange (%s)" % (mode)
+
+ @dbus.service.method("org.bluez.Agent",
+ in_signature="", out_signature="")
+ def Cancel(self):
+ print "Cancel"
+
+def create_device_reply(device):
+ print "New device (%s)" % (device)
+ mainloop.quit()
+
+def create_device_error(error):
+ print "Creating device failed: %s" % (error)
+ mainloop.quit()
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+ if len(sys.argv) > 1:
+ path = manager.FindAdapter(sys.argv[1])
+ else:
+ path = manager.DefaultAdapter()
+
+ adapter = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Adapter")
+
+ path = "/test/agent"
+ agent = Agent(bus, path)
+
+ mainloop = gobject.MainLoop()
+
+ if len(sys.argv) > 2:
+ if len(sys.argv) > 3:
+ device = adapter.FindDevice(sys.argv[2])
+ adapter.RemoveDevice(device)
+
+ agent.set_exit_on_release(False)
+ adapter.CreatePairedDevice(sys.argv[2], path, "DisplayYesNo",
+ reply_handler=create_device_reply,
+ error_handler=create_device_error)
+ else:
+ adapter.RegisterAgent(path, "DisplayYesNo")
+ print "Agent registered"
+
+ mainloop.run()
+
+ #adapter.UnregisterAgent(path)
+ #print "Agent unregistered"
diff --git a/utils/hcid/simple-service b/utils/hcid/simple-service
new file mode 100755
index 00000000..5279a3a6
--- /dev/null
+++ b/utils/hcid/simple-service
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+
+import sys
+import time
+import dbus
+
+xml = ' \
+<?xml version="1.0" encoding="UTF-8" ?> \
+<record> \
+ <attribute id="0x0001"> \
+ <sequence> \
+ <uuid value="0x1101"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0002"> \
+ <uint32 value="0"/> \
+ </attribute> \
+ \
+ <attribute id="0x0003"> \
+ <uuid value="00001101-0000-1000-8000-00805f9b34fb"/> \
+ </attribute> \
+ \
+ <attribute id="0x0004"> \
+ <sequence> \
+ <sequence> \
+ <uuid value="0x0100"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value="0x0003"/> \
+ <uint8 value="23"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0005"> \
+ <sequence> \
+ <uuid value="0x1002"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0006"> \
+ <sequence> \
+ <uint16 value="0x656e"/> \
+ <uint16 value="0x006a"/> \
+ <uint16 value="0x0100"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0007"> \
+ <uint32 value="0"/> \
+ </attribute> \
+ \
+ <attribute id="0x0008"> \
+ <uint8 value="0xff"/> \
+ </attribute> \
+ \
+ <attribute id="0x0009"> \
+ <sequence> \
+ <sequence> \
+ <uuid value="0x1101"/> \
+ <uint16 value="0x0100"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x000a"> \
+ <url value="http://www.bluez.org/"/> \
+ </attribute> \
+ \
+ <attribute id="0x000b"> \
+ <url value="http://www.bluez.org/"/> \
+ </attribute> \
+ \
+ <attribute id="0x000c"> \
+ <url value="http://www.bluez.org/"/> \
+ </attribute> \
+ \
+ <attribute id="0x0100"> \
+ <text value="Serial Port"/> \
+ </attribute> \
+ \
+ <attribute id="0x0101"> \
+ <text value="Serial Port Service"/> \
+ </attribute> \
+ \
+ <attribute id="0x0102"> \
+ <text value="BlueZ"/> \
+ </attribute> \
+ \
+ <attribute id="0x0200"> \
+ <sequence> \
+ <uint16 value="0x0100"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0201"> \
+ <uint32 value="0"/> \
+ </attribute> \
+</record> \
+'
+
+bus = dbus.SystemBus()
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+if len(sys.argv) > 1:
+ path = manager.FindAdapter(sys.argv[1])
+else:
+ path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Adapter")
+
+handle = adapter.AddServiceRecord(xml)
+
+print "Service record with handle 0x%04x added" % (handle)
+
+print "Press CTRL-C to remove service record"
+
+try:
+ time.sleep(1000)
+ print "Terminating session"
+except:
+ pass
+
+adapter.RemoveServiceRecord(dbus.UInt32(handle))
diff --git a/utils/hcid/storage.c b/utils/hcid/storage.c
new file mode 100644
index 00000000..595e9a22
--- /dev/null
+++ b/utils/hcid/storage.c
@@ -0,0 +1,707 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "textfile.h"
+#include "hcid.h"
+
+static inline int create_filename(char *buf, size_t size, const bdaddr_t *bdaddr, const char *name)
+{
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+
+ return create_name(buf, size, STORAGEDIR, addr, name);
+}
+
+int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout)
+{
+ char filename[PATH_MAX + 1], str[32];
+
+ snprintf(str, sizeof(str), "%d", timeout);
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ return textfile_put(filename, "discovto", str);
+}
+
+int read_discoverable_timeout(bdaddr_t *bdaddr, int *timeout)
+{
+ char filename[PATH_MAX + 1], *str;
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ str = textfile_get(filename, "discovto");
+ if (!str)
+ return -ENOENT;
+
+ if (sscanf(str, "%d", timeout) != 1) {
+ free(str);
+ return -ENOENT;
+ }
+
+ free(str);
+
+ return 0;
+}
+
+int write_device_mode(bdaddr_t *bdaddr, const char *mode)
+{
+ char filename[PATH_MAX + 1];
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (strcmp(mode, "off") != 0)
+ textfile_put(filename, "onmode", mode);
+
+ return textfile_put(filename, "mode", mode);
+}
+
+int read_device_mode(bdaddr_t *bdaddr, char *mode, int length)
+{
+ char filename[PATH_MAX + 1], *str;
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ str = textfile_get(filename, "mode");
+ if (!str)
+ return -ENOENT;
+
+ strncpy(mode, str, length);
+ mode[length - 1] = '\0';
+
+ free(str);
+
+ return 0;
+}
+
+int read_on_mode(bdaddr_t *bdaddr, char *mode, int length)
+{
+ char filename[PATH_MAX + 1], *str;
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ str = textfile_get(filename, "onmode");
+ if (!str)
+ return -ENOENT;
+
+ strncpy(mode, str, length);
+ mode[length - 1] = '\0';
+
+ free(str);
+
+ return 0;
+}
+
+int write_local_name(bdaddr_t *bdaddr, char *name)
+{
+ char filename[PATH_MAX + 1], str[249];
+ int i;
+
+ memset(str, 0, sizeof(str));
+ for (i = 0; i < 248 && name[i]; i++)
+ if ((unsigned char) name[i] < 32 || name[i] == 127)
+ str[i] = '.';
+ else
+ str[i] = name[i];
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ return textfile_put(filename, "name", str);
+}
+
+int read_local_name(bdaddr_t *bdaddr, char *name)
+{
+ char filename[PATH_MAX + 1], *str;
+ int len;
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ str = textfile_get(filename, "name");
+ if (!str)
+ return -ENOENT;
+
+ len = strlen(str);
+ if (len > 248)
+ str[248] = '\0';
+ strcpy(name, str);
+
+ free(str);
+
+ return 0;
+}
+
+int write_local_class(bdaddr_t *bdaddr, uint8_t *class)
+{
+ char filename[PATH_MAX + 1], str[9];
+
+ sprintf(str, "0x%2.2x%2.2x%2.2x", class[2], class[1], class[0]);
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ return textfile_put(filename, "class", str);
+}
+
+int read_local_class(bdaddr_t *bdaddr, uint8_t *class)
+{
+ char filename[PATH_MAX + 1], tmp[3], *str;
+ int i;
+
+ create_filename(filename, PATH_MAX, bdaddr, "config");
+
+ str = textfile_get(filename, "class");
+ if (!str)
+ return -ENOENT;
+
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < 3; i++) {
+ memcpy(tmp, str + (i * 2) + 2, 2);
+ class[2 - i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ free(str);
+
+ return 0;
+}
+
+int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
+{
+ char filename[PATH_MAX + 1], addr[18], str[9];
+
+ create_filename(filename, PATH_MAX, local, "classes");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ sprintf(str, "0x%6.6x", class);
+
+ return textfile_put(filename, addr, str);
+}
+
+int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class)
+{
+ char filename[PATH_MAX + 1], addr[18], *str;
+
+ create_filename(filename, PATH_MAX, local, "classes");
+
+ ba2str(peer, addr);
+
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ if (sscanf(str, "%x", class) != 1) {
+ free(str);
+ return -ENOENT;
+ }
+
+ free(str);
+
+ return 0;
+}
+
+int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name)
+{
+ char filename[PATH_MAX + 1], addr[18], str[249];
+ int i;
+
+ memset(str, 0, sizeof(str));
+ for (i = 0; i < 248 && name[i]; i++)
+ if ((unsigned char) name[i] < 32 || name[i] == 127)
+ str[i] = '.';
+ else
+ str[i] = name[i];
+
+ create_filename(filename, PATH_MAX, local, "names");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ return textfile_put(filename, addr, str);
+}
+
+int read_device_name(bdaddr_t *local, bdaddr_t *peer, char *name)
+{
+ char filename[PATH_MAX + 1], addr[18], *str;
+ int len;
+
+ create_filename(filename, PATH_MAX, local, "names");
+
+ ba2str(peer, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ len = strlen(str);
+ if (len > 248)
+ str[248] = '\0';
+ strcpy(name, str);
+
+ free(str);
+
+ return 0;
+}
+
+int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data)
+{
+ char filename[PATH_MAX + 1], addr[18], str[481];
+ int i;
+
+ memset(str, 0, sizeof(str));
+ for (i = 0; i < 240; i++)
+ sprintf(str + (i * 2), "%2.2X", data[i]);
+
+ create_filename(filename, PATH_MAX, local, "eir");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ return textfile_put(filename, addr, str);
+}
+
+int write_l2cap_info(bdaddr_t *local, bdaddr_t *peer,
+ uint16_t mtu_result, uint16_t mtu,
+ uint16_t mask_result, uint32_t mask)
+{
+ char filename[PATH_MAX + 1], addr[18], str[18];
+
+ if (mask_result)
+ snprintf(str, sizeof(str), "%d -1", mtu_result ? -1 : mtu);
+ else
+ snprintf(str, sizeof(str), "%d 0x%08x", mtu_result ? -1 : mtu, mask);
+
+ create_filename(filename, PATH_MAX, local, "l2cap");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ return textfile_put(filename, addr, str);
+}
+
+int read_l2cap_info(bdaddr_t *local, bdaddr_t *peer,
+ uint16_t *mtu_result, uint16_t *mtu,
+ uint16_t *mask_result, uint32_t *mask)
+{
+ char filename[PATH_MAX + 1], addr[18], *str, *space, *msk;
+
+ create_filename(filename, PATH_MAX, local, "l2cap");
+
+ ba2str(peer, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ space = strchr(str, ' ');
+ if (!space) {
+ free(str);
+ return -ENOENT;
+ }
+
+ msk = space + 1;
+ *space = '\0';
+
+ if (mtu_result && mtu) {
+ if (str[0] == '-')
+ *mtu_result = 0x0001;
+ else {
+ *mtu_result = 0;
+ *mtu = (uint16_t) strtol(str, NULL, 0);
+ }
+ }
+
+ if (mask_result && mask) {
+ if (msk[0] == '-')
+ *mask_result = 0x0001;
+ else {
+ *mask_result = 0;
+ *mask = (uint32_t) strtol(msk, NULL, 16);
+ }
+ }
+
+ free(str);
+
+ return 0;
+}
+
+int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver)
+{
+ char filename[PATH_MAX + 1], addr[18], str[16];
+
+ memset(str, 0, sizeof(str));
+ sprintf(str, "%d %d %d", manufacturer, lmp_ver, lmp_subver);
+
+ create_filename(filename, PATH_MAX, local, "manufacturers");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ return textfile_put(filename, addr, str);
+}
+
+int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *features)
+{
+ char filename[PATH_MAX + 1], addr[18], str[17];
+ int i;
+
+ memset(str, 0, sizeof(str));
+ for (i = 0; i < 8; i++)
+ sprintf(str + (i * 2), "%2.2X", features[i]);
+
+ 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);
+}
+
+int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
+{
+ char filename[PATH_MAX + 1], addr[18], str[24];
+
+ memset(str, 0, sizeof(str));
+ strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
+
+ create_filename(filename, PATH_MAX, local, "lastseen");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ return textfile_put(filename, addr, str);
+}
+
+int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
+{
+ char filename[PATH_MAX + 1], addr[18], str[24];
+
+ memset(str, 0, sizeof(str));
+ strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
+
+ create_filename(filename, PATH_MAX, local, "lastused");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ return textfile_put(filename, addr, str);
+}
+
+int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length)
+{
+ char filename[PATH_MAX + 1], addr[18], str[38];
+ int i;
+
+ memset(str, 0, sizeof(str));
+ for (i = 0; i < 16; i++)
+ sprintf(str + (i * 2), "%2.2X", key[i]);
+ sprintf(str + 32, " %d %d", type, length);
+
+ create_filename(filename, PATH_MAX, local, "linkkeys");
+
+ create_file(filename, S_IRUSR | S_IWUSR);
+
+ ba2str(peer, addr);
+
+ if (length < 0) {
+ char *tmp = textfile_get(filename, addr);
+ if (tmp) {
+ if (strlen(tmp) > 34)
+ memcpy(str + 34, tmp + 34, 3);
+ free(tmp);
+ }
+ }
+
+ return textfile_put(filename, addr, str);
+}
+
+int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type)
+{
+ char filename[PATH_MAX + 1], addr[18], tmp[3], *str;
+ int i;
+
+ create_filename(filename, PATH_MAX, local, "linkkeys");
+
+ ba2str(peer, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < 16; i++) {
+ memcpy(tmp, str + (i * 2), 2);
+ key[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ if (type) {
+ memcpy(tmp, str + 33, 2);
+ *type = (uint8_t) strtol(tmp, NULL, 10);
+ }
+
+ free(str);
+
+ return 0;
+}
+
+int read_pin_length(bdaddr_t *local, bdaddr_t *peer)
+{
+ char filename[PATH_MAX + 1], addr[18], *str;
+ int len;
+
+ create_filename(filename, PATH_MAX, local, "linkkeys");
+
+ ba2str(peer, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ if (strlen(str) < 36) {
+ free(str);
+ return -ENOENT;
+ }
+
+ len = atoi(str + 35);
+
+ free(str);
+
+ return len;
+}
+
+int read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin)
+{
+ char filename[PATH_MAX + 1], addr[18], *str;
+ int len;
+
+ create_filename(filename, PATH_MAX, local, "pincodes");
+
+ ba2str(peer, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ strncpy(pin, str, 16);
+ len = strlen(pin);
+
+ free(str);
+
+ return len;
+}
+
+static GSList *service_string_to_list(char *services)
+{
+ GSList *l = NULL;
+ char *start = services;
+ int i, finished = 0;
+
+ for (i = 0; !finished; i++) {
+ if (services[i] == '\0')
+ finished = 1;
+
+ if (services[i] == ' ' || services[i] == '\0') {
+ services[i] = '\0';
+ l = g_slist_append(l, start);
+ start = services + i + 1;
+ }
+ }
+
+ return l;
+}
+
+static char *service_list_to_string(GSList *services)
+{
+ char str[1024];
+ int len = 0;
+
+ if (!services)
+ return g_strdup("");
+
+ memset(str, 0, sizeof(str));
+
+ while (services) {
+ int ret;
+ char *ident = services->data;
+
+ ret = snprintf(str + len, sizeof(str) - len - 1, "%s%s",
+ ident, services->next ? " " : "");
+
+ if (ret > 0)
+ len += ret;
+
+ services = services->next;
+ }
+
+ return g_strdup(str);
+}
+
+int write_trust(bdaddr_t *local, const char *addr, const char *service,
+ gboolean trust)
+{
+ char filename[PATH_MAX + 1], *str;
+ GSList *services = NULL, *match;
+ gboolean trusted;
+ int ret;
+
+ create_filename(filename, PATH_MAX, local, "trusts");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ str = textfile_caseget(filename, addr);
+ if (str)
+ services = service_string_to_list(str);
+
+ match = g_slist_find_custom(services, service, (GCompareFunc) strcmp);
+ trusted = match ? TRUE : FALSE;
+
+ /* If the old setting is the same as the requested one, we're done */
+ if (trusted == trust) {
+ g_slist_free(services);
+ if (str)
+ free(str);
+ return 0;
+ }
+
+ if (trust)
+ services = g_slist_append(services, (void *) service);
+ else
+ services = g_slist_remove(services, match->data);
+
+ /* Remove the entry if the last trusted service was removed */
+ if (!trust && !services)
+ ret = textfile_casedel(filename, addr);
+ else {
+ char *new_str = service_list_to_string(services);
+ ret = textfile_caseput(filename, addr, new_str);
+ free(new_str);
+ }
+
+ g_slist_free(services);
+
+ if (str)
+ free(str);
+
+ return ret;
+}
+
+gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service)
+{
+ char filename[PATH_MAX + 1], *str;
+ GSList *services;
+ gboolean ret;
+
+ create_filename(filename, PATH_MAX, local, "trusts");
+
+ str = textfile_caseget(filename, addr);
+ if (!str)
+ return FALSE;
+
+ services = service_string_to_list(str);
+
+ if (g_slist_find_custom(services, service, (GCompareFunc) strcmp))
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ g_slist_free(services);
+ free(str);
+
+ return ret;
+}
+
+struct trust_list {
+ GSList *trusts;
+ const char *service;
+};
+
+static void append_trust(char *key, char *value, void *data)
+{
+ struct trust_list *list = data;
+
+ if (strstr(value, list->service))
+ list->trusts = g_slist_append(list->trusts, g_strdup(key));
+}
+
+GSList *list_trusts(bdaddr_t *local, const char *service)
+{
+ char filename[PATH_MAX + 1];
+ struct trust_list list;
+
+ create_filename(filename, PATH_MAX, local, "trusts");
+
+ list.trusts = NULL;
+ list.service = service;
+
+ if (textfile_foreach(filename, append_trust, &list) < 0)
+ return NULL;
+
+ return list.trusts;
+}
+
+int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles)
+{
+ char filename[PATH_MAX + 1], addr[18];
+
+ if (!profiles)
+ return -EINVAL;
+
+ create_filename(filename, PATH_MAX, src, "profiles");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(dst, addr);
+ return textfile_put(filename, addr, profiles);
+}
+
+int delete_entry(bdaddr_t *src, const char *storage, const char *key)
+{
+ char filename[PATH_MAX + 1];
+
+ create_filename(filename, PATH_MAX, src, storage);
+
+ return textfile_del(filename, key);
+}
diff --git a/utils/hcid/telephony.c b/utils/hcid/telephony.c
new file mode 100644
index 00000000..f68b97de
--- /dev/null
+++ b/utils/hcid/telephony.c
@@ -0,0 +1,44 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 "telephony.h"
+
+static GSList *drivers = NULL;
+
+int bt_telephony_register_driver(struct bt_telephony_driver *driver)
+{
+ drivers = g_slist_append(drivers, driver);
+
+ return 0;
+}
+
+void bt_telephony_unregister_driver(struct bt_telephony_driver *driver)
+{
+ drivers = g_slist_remove(drivers, driver);
+}
diff --git a/utils/hcid/telephony.h b/utils/hcid/telephony.h
new file mode 100644
index 00000000..b360a621
--- /dev/null
+++ b/utils/hcid/telephony.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct bt_telephony_driver {
+ const char *name;
+};
diff --git a/utils/hcid/test-adapter b/utils/hcid/test-adapter
new file mode 100755
index 00000000..a4612257
--- /dev/null
+++ b/utils/hcid/test-adapter
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+import time
+
+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")
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <command>" % (sys.argv[0])
+ print ""
+ print " address"
+ print " name [name]"
+ print " mode [mode]"
+ print " requestmode <mode>"
+ print " discoverabletimeout [timeout]"
+ print " periodicdiscovery [on/off]"
+ print " addservicerecord <file>"
+ sys.exit(1)
+
+if (sys.argv[1] == "address"):
+ properties = adapter.GetProperties()
+ print properties["Address"]
+ sys.exit(0)
+
+if (sys.argv[1] == "name"):
+ if (len(sys.argv) < 3):
+ properties = adapter.GetProperties()
+ print properties["Name"]
+ else:
+ adapter.SetProperty("Name", sys.argv[2])
+ sys.exit(0)
+
+if (sys.argv[1] == "mode"):
+ if (len(sys.argv) < 3):
+ properties = adapter.GetProperties()
+ print properties["Mode"]
+ else:
+ adapter.SetProperty("Mode", sys.argv[2])
+ sys.exit(0)
+
+if (sys.argv[1] == "requestmode"):
+ if (len(sys.argv) < 3):
+ print "Need mode parameter"
+ else:
+ adapter.RequestMode(sys.argv[2])
+ sys.exit(0)
+
+if (sys.argv[1] == "discoverabletimeout"):
+ if (len(sys.argv) < 3):
+ properties = adapter.GetProperties()
+ print properties["DiscoverableTimeout"]
+ else:
+ adapter.SetProperty("DiscoverableTimeout", sys.argv[2])
+ sys.exit(0)
+
+if (sys.argv[1] == "periodicdiscovery"):
+ if (len(sys.argv) < 3):
+ properties = adapter.GetProperties()
+ print properties["PeriodicDiscovery"]
+ else:
+ if (sys.argv[2] == "on"):
+ value = dbus.Boolean(1)
+ elif (sys.argv[2] == "off"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(sys.argv[2])
+ adapter.SetProperty("PeriodicDiscovery", value)
+ time.sleep(120)
+ sys.exit(0)
+
+if (sys.argv[1] == "addservicerecord"):
+ if (len(sys.argv) < 3):
+ print "Need file parameter"
+ else:
+ f = open(sys.argv[2])
+ record = f.read()
+ f.close()
+ handle = adapter.AddServiceRecord(record)
+ print "0x%x" % (handle)
+ time.sleep(120)
+ sys.exit(0)
+
+print "Unknown command"
+sys.exit(1)
diff --git a/utils/hcid/test-device b/utils/hcid/test-device
new file mode 100755
index 00000000..05a23d37
--- /dev/null
+++ b/utils/hcid/test-device
@@ -0,0 +1,124 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+import re
+
+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")
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <command>" % (sys.argv[0])
+ print ""
+ print " list"
+ print " create <address>"
+ print " remove <path>"
+ print " discover <address> [pattern]"
+ print " class <address>"
+ print " name <address>"
+ print " alias <address> [alias]"
+ print " trusted <address> [yes/no]"
+ sys.exit(1)
+
+if (sys.argv[1] == "list"):
+ list = adapter.ListDevices()
+ print list
+ sys.exit(0)
+
+if (sys.argv[1] == "create"):
+ if (len(sys.argv) < 3):
+ print "Need address parameter"
+ else:
+ device = adapter.CreateDevice(sys.argv[2])
+ print device
+ sys.exit(0)
+
+if (sys.argv[1] == "remove"):
+ if (len(sys.argv) < 3):
+ print "Need object path parameter"
+ else:
+ adapter.RemoveDevice(sys.argv[2])
+ sys.exit(0)
+
+if (sys.argv[1] == "discover"):
+ if (len(sys.argv) < 3):
+ print "Need address parameter"
+ else:
+ path = adapter.FindDevice(sys.argv[2])
+ device = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device")
+ if (len(sys.argv) < 4):
+ pattern = ""
+ else:
+ pattern = sys.argv[3]
+ services = device.DiscoverServices(pattern);
+ for key in services.keys():
+ p = re.compile(">.*?<")
+ xml = p.sub("><", services[key].replace("\n", ""))
+ print "[ 0x%5x ]" % (key)
+ print xml
+ print
+ sys.exit(0)
+
+if (sys.argv[1] == "class"):
+ if (len(sys.argv) < 3):
+ print "Need address parameter"
+ else:
+ path = adapter.FindDevice(sys.argv[2])
+ 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):
+ print "Need address parameter"
+ else:
+ path = adapter.FindDevice(sys.argv[2])
+ 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):
+ print "Need address parameter"
+ else:
+ path = adapter.FindDevice(sys.argv[2])
+ device = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device")
+ if (len(sys.argv) < 4):
+ properties = device.GetProperties()
+ print properties["Alias"]
+ else:
+ device.SetProperty("Alias", sys.argv[3])
+ sys.exit(0)
+
+if (sys.argv[1] == "trusted"):
+ if (len(sys.argv) < 3):
+ print "Need address parameter"
+ else:
+ path = adapter.FindDevice(sys.argv[2])
+ device = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device")
+ if (len(sys.argv) < 4):
+ properties = device.GetProperties()
+ print properties["Trusted"]
+ else:
+ if (sys.argv[3] == "yes"):
+ value = dbus.Boolean(1)
+ elif (sys.argv[3] == "no"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(sys.argv[3])
+ device.SetProperty("Trusted", value)
+ sys.exit(0)
+
+print "Unknown command"
+sys.exit(1)
diff --git a/utils/hcid/test-discovery b/utils/hcid/test-discovery
new file mode 100755
index 00000000..874de66f
--- /dev/null
+++ b/utils/hcid/test-discovery
@@ -0,0 +1,43 @@
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+def device_found(address, properties):
+ print "[ " + address + " ]"
+
+ for key in properties.keys():
+ value = properties[key]
+ if (key == "Class"):
+ print " %s = 0x%06x" % (key, value)
+ else:
+ print " %s = %s" % (key, value)
+
+def discovery_completed():
+ mainloop.quit()
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+ path = manager.DefaultAdapter()
+ adapter = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Adapter")
+
+ bus.add_signal_receiver(device_found,
+ dbus_interface = "org.bluez.Adapter",
+ signal_name = "DeviceFound")
+
+ bus.add_signal_receiver(discovery_completed,
+ dbus_interface = "org.bluez.Adapter",
+ signal_name = "DiscoveryCompleted")
+
+ adapter.DiscoverDevices()
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
diff --git a/utils/hcid/test-manager b/utils/hcid/test-manager
new file mode 100755
index 00000000..759b6a48
--- /dev/null
+++ b/utils/hcid/test-manager
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+def adapter_added(path):
+ print "Adapter with path %s added" % (path)
+
+def adapter_removed(path):
+ print "Adapter with path %s removed" % (path)
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Manager')
+
+ manager.connect_to_signal("AdapterAdded", adapter_added)
+
+ manager.connect_to_signal("AdapterRemoved", adapter_removed)
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
diff --git a/utils/hidd/Makefile.am b/utils/hidd/Makefile.am
new file mode 100644
index 00000000..508372b4
--- /dev/null
+++ b/utils/hidd/Makefile.am
@@ -0,0 +1,22 @@
+
+if HIDD
+bin_PROGRAMS = hidd
+
+hidd_SOURCES = main.c hidd.h sdp.c fakehid.c
+
+hidd_LDADD = @BLUEZ_LIBS@ -lm $(top_builddir)/common/libhelper.a
+endif
+
+AM_CFLAGS = @BLUEZ_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common
+
+if HIDD
+if MANPAGES
+man_MANS = hidd.1
+endif
+endif
+
+EXTRA_DIST = hidd.1 fakehid.txt
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/hidd/Makefile.in b/utils/hidd/Makefile.in
new file mode 100644
index 00000000..d46886cd
--- /dev/null
+++ b/utils/hidd/Makefile.in
@@ -0,0 +1,540 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HIDD_TRUE@bin_PROGRAMS = hidd$(EXEEXT)
+subdir = hidd
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__hidd_SOURCES_DIST = main.c hidd.h sdp.c fakehid.c
+@HIDD_TRUE@am_hidd_OBJECTS = main.$(OBJEXT) sdp.$(OBJEXT) \
+@HIDD_TRUE@ fakehid.$(OBJEXT)
+hidd_OBJECTS = $(am_hidd_OBJECTS)
+@HIDD_TRUE@hidd_DEPENDENCIES = $(top_builddir)/common/libhelper.a
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(hidd_SOURCES)
+DIST_SOURCES = $(am__hidd_SOURCES_DIST)
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@HIDD_TRUE@hidd_SOURCES = main.c hidd.h sdp.c fakehid.c
+@HIDD_TRUE@hidd_LDADD = @BLUEZ_LIBS@ -lm $(top_builddir)/common/libhelper.a
+AM_CFLAGS = @BLUEZ_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
+@HIDD_TRUE@@MANPAGES_TRUE@man_MANS = hidd.1
+EXTRA_DIST = hidd.1 fakehid.txt
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu hidd/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu hidd/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+hidd$(EXEEXT): $(hidd_OBJECTS) $(hidd_DEPENDENCIES)
+ @rm -f hidd$(EXEEXT)
+ $(LINK) $(hidd_OBJECTS) $(hidd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fakehid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdp.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(man1_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-man \
+ uninstall-man1
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/hidd/fakehid.c b/utils/hidd/fakehid.c
new file mode 100644
index 00000000..feefe2a6
--- /dev/null
+++ b/utils/hidd/fakehid.c
@@ -0,0 +1,669 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/hidp.h>
+
+#include "hidd.h"
+#include "uinput.h"
+
+#include <math.h>
+
+#ifdef NEED_PPOLL
+#include "ppoll.h"
+#endif
+
+static volatile sig_atomic_t __io_canceled = 0;
+
+static void sig_hup(int sig)
+{
+}
+
+static void sig_term(int sig)
+{
+ __io_canceled = 1;
+}
+
+static void send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct uinput_event event;
+ int len;
+
+ if (fd <= fileno(stderr))
+ return;
+
+ memset(&event, 0, sizeof(event));
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ len = write(fd, &event, sizeof(event));
+}
+
+static int uinput_create(char *name, int keyboard, int mouse)
+{
+ struct uinput_dev dev;
+ int fd, aux;
+
+ fd = open("/dev/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/input/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/misc/uinput", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open input device: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+ }
+ }
+
+ memset(&dev, 0, sizeof(dev));
+
+ if (name)
+ strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
+
+ dev.id.bustype = BUS_BLUETOOTH;
+ dev.id.vendor = 0x0000;
+ dev.id.product = 0x0000;
+ dev.id.version = 0x0000;
+
+ if (write(fd, &dev, sizeof(dev)) < 0) {
+ fprintf(stderr, "Can't write device information: %s (%d)\n",
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ if (mouse) {
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+
+ for (aux = REL_X; aux <= REL_MISC; aux++)
+ ioctl(fd, UI_SET_RELBIT, aux);
+ }
+
+ if (keyboard) {
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_EVBIT, EV_LED);
+ ioctl(fd, UI_SET_EVBIT, EV_REP);
+
+ for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++)
+ ioctl(fd, UI_SET_KEYBIT, aux);
+
+ //for (aux = LED_NUML; aux <= LED_MISC; aux++)
+ // ioctl(fd, UI_SET_LEDBIT, aux);
+ }
+
+ if (mouse) {
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+
+ for (aux = BTN_LEFT; aux <= BTN_BACK; aux++)
+ ioctl(fd, UI_SET_KEYBIT, aux);
+ }
+
+ ioctl(fd, UI_DEV_CREATE);
+
+ return fd;
+}
+
+static int rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
+{
+ struct sockaddr_rc addr;
+ int sk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ fprintf(stderr, "Can't create socket: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ fprintf(stderr, "Can't bind socket: %s (%d)\n",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, dst);
+ addr.rc_channel = channel;
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ fprintf(stderr, "Can't connect: %s (%d)\n",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+
+ return sk;
+}
+
+static void func(int fd)
+{
+}
+
+static void back(int fd)
+{
+}
+
+static void next(int fd)
+{
+}
+
+static void button(int fd, unsigned int button, int is_press)
+{
+ switch (button) {
+ case 1:
+ send_event(fd, EV_KEY, BTN_LEFT, is_press);
+ break;
+ case 3:
+ send_event(fd, EV_KEY, BTN_RIGHT, is_press);
+ break;
+ }
+
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+static void move(int fd, unsigned int direction)
+{
+ double angle;
+ int32_t x, y;
+
+ angle = (direction * 22.5) * 3.1415926 / 180;
+ x = (int) (sin(angle) * 8);
+ y = (int) (cos(angle) * -8);
+
+ send_event(fd, EV_REL, REL_X, x);
+ send_event(fd, EV_REL, REL_Y, y);
+
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+static inline void epox_decode(int fd, unsigned char event)
+{
+ switch (event) {
+ case 48:
+ func(fd); break;
+ case 55:
+ back(fd); break;
+ case 56:
+ next(fd); break;
+ case 53:
+ button(fd, 1, 1); break;
+ case 121:
+ button(fd, 1, 0); break;
+ case 113:
+ break;
+ case 54:
+ button(fd, 3, 1); break;
+ case 120:
+ button(fd, 3, 0); break;
+ case 112:
+ break;
+ case 51:
+ move(fd, 0); break;
+ case 97:
+ move(fd, 1); break;
+ case 65:
+ move(fd, 2); break;
+ case 98:
+ move(fd, 3); break;
+ case 50:
+ move(fd, 4); break;
+ case 99:
+ move(fd, 5); break;
+ case 67:
+ move(fd, 6); break;
+ case 101:
+ move(fd, 7); break;
+ case 52:
+ move(fd, 8); break;
+ case 100:
+ move(fd, 9); break;
+ case 66:
+ move(fd, 10); break;
+ case 102:
+ move(fd, 11); break;
+ case 49:
+ move(fd, 12); break;
+ case 103:
+ move(fd, 13); break;
+ case 57:
+ move(fd, 14); break;
+ case 104:
+ move(fd, 15); break;
+ case 69:
+ break;
+ default:
+ printf("Unknown event code %d\n", event);
+ break;
+ }
+}
+
+int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
+{
+ unsigned char buf[16];
+ struct sigaction sa;
+ struct pollfd p;
+ sigset_t sigs;
+ char addr[18];
+ int i, fd, sk, len;
+
+ sk = rfcomm_connect(src, dst, channel);
+ if (sk < 0)
+ return -1;
+
+ fd = uinput_create("Bluetooth Presenter", 0, 1);
+ if (fd < 0) {
+ close(sk);
+ return -1;
+ }
+
+ ba2str(dst, addr);
+
+ printf("Connected to %s on channel %d\n", addr, channel);
+ printf("Press CTRL-C for hangup\n");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ p.fd = sk;
+ p.events = POLLIN | POLLERR | POLLHUP;
+
+ while (!__io_canceled) {
+ p.revents = 0;
+ if (ppoll(&p, 1, NULL, &sigs) < 1)
+ continue;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len < 0)
+ break;
+
+ for (i = 0; i < len; i++)
+ epox_decode(fd, buf[i]);
+ }
+
+ printf("Disconnected\n");
+
+ ioctl(fd, UI_DEV_DESTROY);
+
+ close(fd);
+ close(sk);
+
+ return 0;
+}
+
+int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
+{
+ printf("Not implemented\n");
+ return -1;
+}
+
+/* The strange meta key close to Ctrl has been assigned to Esc,
+ Fn key to CtrlR and the left space to Alt*/
+
+static unsigned char jthree_keycodes[63] = {
+ KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,
+ KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T,
+ KEY_A, KEY_S, KEY_D, KEY_F, KEY_G,
+ KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B,
+ KEY_LEFTALT, KEY_TAB, KEY_CAPSLOCK, KEY_ESC,
+ KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE,
+ KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE,
+ KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER,
+ KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_UP,
+ KEY_SPACE, KEY_COMPOSE, KEY_LEFT, KEY_DOWN, KEY_RIGHT,
+ KEY_LEFTCTRL, KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_DELETE, KEY_RIGHTCTRL, KEY_RIGHTALT,
+};
+
+static inline void jthree_decode(int fd, unsigned char event)
+{
+ if (event > 63)
+ send_event(fd, EV_KEY, jthree_keycodes[event & 0x3f], 0);
+ else
+ send_event(fd, EV_KEY, jthree_keycodes[event - 1], 1);
+}
+
+int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
+{
+ unsigned char buf[16];
+ struct sigaction sa;
+ struct pollfd p;
+ sigset_t sigs;
+ char addr[18];
+ int i, fd, sk, len;
+
+ sk = rfcomm_connect(src, dst, channel);
+ if (sk < 0)
+ return -1;
+
+ fd = uinput_create("J-Three Keyboard", 1, 0);
+ if (fd < 0) {
+ close(sk);
+ return -1;
+ }
+
+ ba2str(dst, addr);
+
+ printf("Connected to %s on channel %d\n", addr, channel);
+ printf("Press CTRL-C for hangup\n");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ p.fd = sk;
+ p.events = POLLIN | POLLERR | POLLHUP;
+
+ while (!__io_canceled) {
+ p.revents = 0;
+ if (ppoll(&p, 1, NULL, &sigs) < 1)
+ continue;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len < 0)
+ break;
+
+ for (i = 0; i < len; i++)
+ jthree_decode(fd, buf[i]);
+ }
+
+ printf("Disconnected\n");
+
+ ioctl(fd, UI_DEV_DESTROY);
+
+ close(fd);
+ close(sk);
+
+ return 0;
+}
+
+static const int celluon_xlate_num[10] = {
+ KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9
+};
+
+static const int celluon_xlate_char[26] = {
+ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
+ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z
+};
+
+static int celluon_xlate(int c)
+{
+ if (c >= '0' && c <= '9')
+ return celluon_xlate_num[c - '0'];
+
+ if (c >= 'A' && c <= 'Z')
+ return celluon_xlate_char[c - 'A'];
+
+ switch (c) {
+ case 0x08:
+ return KEY_BACKSPACE;
+ case 0x09:
+ return KEY_TAB;
+ case 0x0d:
+ return KEY_ENTER;
+ case 0x11:
+ return KEY_LEFTCTRL;
+ case 0x14:
+ return KEY_CAPSLOCK;
+ case 0x20:
+ return KEY_SPACE;
+ case 0x25:
+ return KEY_LEFT;
+ case 0x26:
+ return KEY_UP;
+ case 0x27:
+ return KEY_RIGHT;
+ case 0x28:
+ return KEY_DOWN;
+ case 0x2e:
+ return KEY_DELETE;
+ case 0x5b:
+ return KEY_MENU;
+ case 0xa1:
+ return KEY_RIGHTSHIFT;
+ case 0xa0:
+ return KEY_LEFTSHIFT;
+ case 0xba:
+ return KEY_SEMICOLON;
+ case 0xbd:
+ return KEY_MINUS;
+ case 0xbc:
+ return KEY_COMMA;
+ case 0xbb:
+ return KEY_EQUAL;
+ case 0xbe:
+ return KEY_DOT;
+ case 0xbf:
+ return KEY_SLASH;
+ case 0xc0:
+ return KEY_GRAVE;
+ case 0xdb:
+ return KEY_LEFTBRACE;
+ case 0xdc:
+ return KEY_BACKSLASH;
+ case 0xdd:
+ return KEY_RIGHTBRACE;
+ case 0xde:
+ return KEY_APOSTROPHE;
+ case 0xff03:
+ return KEY_HOMEPAGE;
+ case 0xff04:
+ return KEY_TIME;
+ case 0xff06:
+ return KEY_OPEN;
+ case 0xff07:
+ return KEY_LIST;
+ case 0xff08:
+ return KEY_MAIL;
+ case 0xff30:
+ return KEY_CALC;
+ case 0xff1a: /* Map FN to ALT */
+ return KEY_LEFTALT;
+ case 0xff2f:
+ return KEY_INFO;
+ default:
+ printf("Unknown key %x\n", c);
+ return c;
+ }
+}
+
+struct celluon_state {
+ int len; /* Expected length of current packet */
+ int count; /* Number of bytes received */
+ int action;
+ int key;
+};
+
+static void celluon_decode(int fd, struct celluon_state *s, uint8_t c)
+{
+ if (s->count < 2 && c != 0xa5) {
+ /* Lost Sync */
+ s->count = 0;
+ return;
+ }
+
+ switch (s->count) {
+ case 0:
+ /* New packet - Reset state */
+ s->len = 30;
+ s->key = 0;
+ break;
+ case 1:
+ break;
+ case 6:
+ s->action = c;
+ break;
+ case 28:
+ s->key = c;
+ if (c == 0xff)
+ s->len = 31;
+ break;
+ case 29:
+ case 30:
+ if (s->count == s->len - 1) {
+ /* TODO: Verify checksum */
+ if (s->action < 2) {
+ send_event(fd, EV_KEY, celluon_xlate(s->key),
+ s->action);
+ }
+ s->count = -1;
+ } else {
+ s->key = (s->key << 8) | c;
+ }
+ break;
+ }
+
+ s->count++;
+
+ return;
+}
+
+int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
+{
+ unsigned char buf[16];
+ struct sigaction sa;
+ struct pollfd p;
+ sigset_t sigs;
+ char addr[18];
+ int i, fd, sk, len;
+ struct celluon_state s;
+
+ sk = rfcomm_connect(src, dst, channel);
+ if (sk < 0)
+ return -1;
+
+ fd = uinput_create("Celluon Keyboard", 1, 0);
+ if (fd < 0) {
+ close(sk);
+ return -1;
+ }
+
+ ba2str(dst, addr);
+
+ printf("Connected to %s on channel %d\n", addr, channel);
+ printf("Press CTRL-C for hangup\n");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ p.fd = sk;
+ p.events = POLLIN | POLLERR | POLLHUP;
+
+ memset(&s, 0, sizeof(s));
+
+ while (!__io_canceled) {
+ p.revents = 0;
+ if (ppoll(&p, 1, NULL, &sigs) < 1)
+ continue;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len < 0)
+ break;
+
+ for (i = 0; i < len; i++)
+ celluon_decode(fd, &s, buf[i]);
+ }
+
+ printf("Disconnected\n");
+
+ ioctl(fd, UI_DEV_DESTROY);
+
+ close(fd);
+ close(sk);
+
+ return 0;
+}
diff --git a/utils/hidd/fakehid.txt b/utils/hidd/fakehid.txt
new file mode 100644
index 00000000..000d0ee2
--- /dev/null
+++ b/utils/hidd/fakehid.txt
@@ -0,0 +1,134 @@
+EPox Presenter
+==============
+
+# hcitool inq
+Inquiring ...
+ 00:04:61:aa:bb:cc clock offset: 0x1ded class: 0x004000
+
+# hcitool info 00:04:61:aa:bb:cc
+Requesting information ...
+ BD Address: 00:04:61:aa:bb:cc
+ OUI Company: EPOX Computer Co., Ltd. (00-04-61)
+ Device Name: EPox BT-PM01B aabbcc
+ LMP Version: 1.1 (0x1) LMP Subversion: 0xf78
+ Manufacturer: Cambridge Silicon Radio (10)
+ Features: 0xff 0xff 0x0f 0x00 0x00 0x00 0x00 0x00
+ <3-slot packets> <5-slot packets> <encryption> <slot offset>
+ <timing accuracy> <role switch> <hold mode> <sniff mode>
+ <park state> <RSSI> <channel quality> <SCO link> <HV2 packets>
+ <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme>
+ <power control> <transparent SCO>
+
+# sdptool records --raw 00:04:61:aa:bb:cc
+Sequence
+ Attribute 0x0000 - ServiceRecordHandle
+ UINT32 0x00010000
+ Attribute 0x0001 - ServiceClassIDList
+ Sequence
+ UUID16 0x1101 - SerialPort
+ Attribute 0x0004 - ProtocolDescriptorList
+ Sequence
+ Sequence
+ UUID16 0x0100 - L2CAP
+ Sequence
+ UUID16 0x0003 - RFCOMM
+ UINT8 0x01
+ Attribute 0x0100
+ String Cable Replacement
+
+
+J-Three Keyboard
+================
+
+# hcitool inq
+Inquiring ...
+ 00:0A:3A:aa:bb:cc clock offset: 0x3039 class: 0x001f00
+
+# hcitool info 00:0A:3A:aa:bb:cc
+Password:
+Requesting information ...
+ BD Address: 00:0A:3A:aa:bb:cc
+ OUI Company: J-THREE INTERNATIONAL Holding Co., Ltd. (00-0A-3A)
+ Device Name: KEYBOARD
+ LMP Version: 1.1 (0x1) LMP Subversion: 0x2c2
+ Manufacturer: Cambridge Silicon Radio (10)
+ Features: 0xbc 0x06 0x07 0x00 0x00 0x00 0x00 0x00
+ <encryption> <slot offset> <timing accuracy> <role switch>
+ <sniff mode> <RSSI> <channel quality> <CVSD> <paging scheme>
+ <power control>
+
+# sdptool records --raw 00:0A:3A:aa:bb:cc
+Sequence
+ Attribute 0x0000 - ServiceRecordHandle
+ UINT32 0x00010000
+ Attribute 0x0001 - ServiceClassIDList
+ Sequence
+ UUID16 0x1101 - SerialPort
+ Attribute 0x0004 - ProtocolDescriptorList
+ Sequence
+ Sequence
+ UUID16 0x0100 - L2CAP
+ Sequence
+ UUID16 0x0003 - RFCOMM
+ UINT8 0x01
+ Attribute 0x0006 - LanguageBaseAttributeIDList
+ Sequence
+ UINT16 0x656e
+ UINT16 0x006a
+ UINT16 0x0100
+ Attribute 0x0100
+ String SPP slave
+
+
+Celluon Laserkey Keyboard
+=========================
+
+# hcitool inq
+Inquiring ...
+ 00:0B:24:aa:bb:cc clock offset: 0x3ab6 class: 0x400210
+
+# hcitool info 00:0B:24:aa:bb:cc
+Requesting information ...
+ BD Address: 00:0B:24:aa:bb:cc
+ OUI Company: AirLogic (00-0B-24)
+ Device Name: CL800BT
+ LMP Version: 1.1 (0x1) LMP Subversion: 0x291
+ Manufacturer: Cambridge Silicon Radio (10)
+ Features: 0xff 0xff 0x0f 0x00 0x00 0x00 0x00 0x00
+ <3-slot packets> <5-slot packets> <encryption> <slot offset>
+ <timing accuracy> <role switch> <hold mode> <sniff mode>
+ <park state> <RSSI> <channel quality> <SCO link> <HV2 packets>
+ <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme>
+ <power control> <transparent SCO>
+
+# sdptool records --raw 00:0B:24:aa:bb:cc
+Sequence
+ Attribute 0x0000 - ServiceRecordHandle
+ UINT32 0x00010000
+ Attribute 0x0001 - ServiceClassIDList
+ Sequence
+ UUID16 0x1101 - SerialPort
+ Attribute 0x0004 - ProtocolDescriptorList
+ Sequence
+ Sequence
+ UUID16 0x0100 - L2CAP
+ Sequence
+ UUID16 0x0003 - RFCOMM
+ UINT8 0x01
+ Attribute 0x0100
+ String Serial Port
+
+Packet format is as follows (all fields little-endian):
+ 0 uint16 magic # 0x5a5a
+ 2 uint32 unknown # ???
+ 6 uint8 action # 0 = keyup, 1 = keydown, 2 = repeat
+ # 3, 4, 5, 6 = ??? (Mouse mode)
+ 7 uint8 unknown[9] # ???
+ 16 uint8 action2 # ??? same as action
+ 17 uint16 x # Horizontal coordinate
+ 19 uint16 y # Vertical coordinate
+ 21 uint16 time # Some sort of timestamp
+ 23 uint8 unknown[5] # ???
+ 28 uint8 key[] # single byte keycode or 0xff byte
+ # follwed by special keycode byte.
+ Each packet followed by a checksum byte.
diff --git a/utils/hidd/hidd.1 b/utils/hidd/hidd.1
new file mode 100644
index 00000000..b186ac24
--- /dev/null
+++ b/utils/hidd/hidd.1
@@ -0,0 +1,41 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.33.
+.TH HIDD "1" "May 2004" "hidd - Bluetooth HID daemon" "User Commands"
+.SH NAME
+hidd \- Bluetooth HID daemon
+.SH DESCRIPTION
+hidd - Bluetooth HID daemon
+.SS "Usage:"
+.IP
+hidd [options] [commands]
+.SH OPTIONS
+.TP
+\fB\-i\fR <hciX|bdaddr>
+Local HCI device or BD Address
+.TP
+\fB\-t\fR <timeout>
+Set idle timeout (in minutes)
+.TP
+\fB\-n\fR, \fB\-\-nodaemon\fR
+Don't fork daemon to background
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Display help
+.SS "Commands:"
+.TP
+\fB\-\-server\fR
+Start HID server
+.TP
+\fB\-\-search\fR
+Search for HID devices
+.TP
+\fB\-\-connect\fR <bdaddr>
+Connect remote HID device
+.TP
+\fB\-\-kill\fR <bdaddr>
+Terminate HID connection
+.TP
+\fB\-\-killall\fR
+Terminate all connections
+.TP
+\fB\-\-show\fR
+List current HID connections
diff --git a/utils/hidd/hidd.h b/utils/hidd/hidd.h
new file mode 100644
index 00000000..63e0cbbe
--- /dev/null
+++ b/utils/hidd/hidd.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define L2CAP_PSM_HIDP_CTRL 0x11
+#define L2CAP_PSM_HIDP_INTR 0x13
+
+int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req);
+int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req);
+int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len);
+
+int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
+int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
+int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
+int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
diff --git a/utils/hidd/main.c b/utils/hidd/main.c
new file mode 100644
index 00000000..d0883b36
--- /dev/null
+++ b/utils/hidd/main.c
@@ -0,0 +1,860 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/hidp.h>
+
+#include "hidd.h"
+
+#ifdef NEED_PPOLL
+#include "ppoll.h"
+#endif
+
+enum {
+ NONE,
+ SHOW,
+ SERVER,
+ SEARCH,
+ CONNECT,
+ KILL
+};
+
+static volatile sig_atomic_t __io_canceled = 0;
+
+static void sig_hup(int sig)
+{
+}
+
+static void sig_term(int sig)
+{
+ __io_canceled = 1;
+}
+
+static int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm)
+{
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ int sk;
+
+ if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ memset(&opts, 0, sizeof(opts));
+ opts.imtu = HIDP_DEFAULT_MTU;
+ opts.omtu = HIDP_DEFAULT_MTU;
+ opts.flush_to = 0xffff;
+
+ setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(psm);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ return sk;
+}
+
+static int l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm, int lm, int backlog)
+{
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ int sk;
+
+ if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, bdaddr);
+ addr.l2_psm = htobs(psm);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm));
+
+ memset(&opts, 0, sizeof(opts));
+ opts.imtu = HIDP_DEFAULT_MTU;
+ opts.omtu = HIDP_DEFAULT_MTU;
+ opts.flush_to = 0xffff;
+
+ setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));
+
+ if (listen(sk, backlog) < 0) {
+ close(sk);
+ return -1;
+ }
+
+ return sk;
+}
+
+static int l2cap_accept(int sk, bdaddr_t *bdaddr)
+{
+ struct sockaddr_l2 addr;
+ socklen_t addrlen;
+ int nsk;
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+
+ if ((nsk = accept(sk, (struct sockaddr *) &addr, &addrlen)) < 0)
+ return -1;
+
+ if (bdaddr)
+ bacpy(bdaddr, &addr.l2_bdaddr);
+
+ return nsk;
+}
+
+static int request_authentication(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct hci_conn_info_req *cr;
+ char addr[18];
+ int err, dd, dev_id;
+
+ ba2str(src, addr);
+ dev_id = hci_devid(addr);
+ if (dev_id < 0)
+ return dev_id;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0)
+ return dd;
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr)
+ return -ENOMEM;
+
+ bacpy(&cr->bdaddr, dst);
+ cr->type = ACL_LINK;
+ err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr);
+ if (err < 0) {
+ free(cr);
+ hci_close_dev(dd);
+ return err;
+ }
+
+ err = hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000);
+
+ free(cr);
+ hci_close_dev(dd);
+
+ return err;
+}
+
+static int request_encryption(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct hci_conn_info_req *cr;
+ char addr[18];
+ int err, dd, dev_id;
+
+ ba2str(src, addr);
+ dev_id = hci_devid(addr);
+ if (dev_id < 0)
+ return dev_id;
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0)
+ return dd;
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr)
+ return -ENOMEM;
+
+ bacpy(&cr->bdaddr, dst);
+ cr->type = ACL_LINK;
+ err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr);
+ if (err < 0) {
+ free(cr);
+ hci_close_dev(dd);
+ return err;
+ }
+
+ err = hci_encrypt_link(dd, htobs(cr->conn_info->handle), 1, 25000);
+
+ free(cr);
+ hci_close_dev(dd);
+
+ return err;
+}
+
+static void enable_sixaxis(int csk)
+{
+ const unsigned char buf[] = {
+ 0x53 /*HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE*/,
+ 0xf4, 0x42, 0x03, 0x00, 0x00 };
+ int err;
+
+ err = write(csk, buf, sizeof(buf));
+}
+
+static int create_device(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout)
+{
+ struct hidp_connadd_req req;
+ struct sockaddr_l2 addr;
+ socklen_t addrlen;
+ bdaddr_t src, dst;
+ char bda[18];
+ int err;
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+
+ if (getsockname(csk, (struct sockaddr *) &addr, &addrlen) < 0)
+ return -1;
+
+ bacpy(&src, &addr.l2_bdaddr);
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+
+ if (getpeername(csk, (struct sockaddr *) &addr, &addrlen) < 0)
+ return -1;
+
+ bacpy(&dst, &addr.l2_bdaddr);
+
+ memset(&req, 0, sizeof(req));
+ req.ctrl_sock = csk;
+ req.intr_sock = isk;
+ req.flags = 0;
+ req.idle_to = timeout * 60;
+
+ err = get_stored_device_info(&src, &dst, &req);
+ if (!err)
+ goto create;
+
+ if (!nocheck) {
+ ba2str(&dst, bda);
+ syslog(LOG_ERR, "Rejected connection from unknown device %s", bda);
+ /* Return no error to avoid run_server() complaining too */
+ return 0;
+ }
+
+ if (!nosdp) {
+ err = get_sdp_device_info(&src, &dst, &req);
+ if (err < 0)
+ goto error;
+ } else {
+ struct l2cap_conninfo conn;
+ socklen_t size;
+ uint8_t class[3];
+
+ memset(&conn, 0, sizeof(conn));
+ size = sizeof(conn);
+ if (getsockopt(csk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &size) < 0)
+ memset(class, 0, 3);
+ else
+ memcpy(class, conn.dev_class, 3);
+
+ if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01))
+ req.subclass = class[0];
+ else
+ req.subclass = 0xc0;
+ }
+
+create:
+ if (subclass != 0x00)
+ req.subclass = subclass;
+
+ ba2str(&dst, bda);
+ syslog(LOG_INFO, "New HID device %s (%s)", bda, req.name);
+
+ if (encrypt && (req.subclass & 0x40)) {
+ err = request_authentication(&src, &dst);
+ if (err < 0) {
+ syslog(LOG_ERR, "Authentication for %s failed", bda);
+ goto error;
+ }
+
+ err = request_encryption(&src, &dst);
+ if (err < 0)
+ syslog(LOG_ERR, "Encryption for %s failed", bda);
+ }
+
+ if (bootonly) {
+ req.rd_size = 0;
+ req.flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
+ }
+
+ if (req.vendor == 0x054c && req.product == 0x0268)
+ enable_sixaxis(csk);
+
+ err = ioctl(ctl, HIDPCONNADD, &req);
+
+error:
+ if (req.rd_data)
+ free(req.rd_data);
+
+ return err;
+}
+
+static void run_server(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout)
+{
+ struct pollfd p[2];
+ sigset_t sigs;
+ short events;
+ int err, ncsk, nisk;
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ p[0].fd = csk;
+ p[0].events = POLLIN | POLLERR | POLLHUP;
+
+ p[1].fd = isk;
+ p[1].events = POLLIN | POLLERR | POLLHUP;
+
+ while (!__io_canceled) {
+ p[0].revents = 0;
+ p[1].revents = 0;
+
+ if (ppoll(p, 2, NULL, &sigs) < 1)
+ continue;
+
+ events = p[0].revents | p[1].revents;
+
+ if (events & POLLIN) {
+ ncsk = l2cap_accept(csk, NULL);
+ nisk = l2cap_accept(isk, NULL);
+
+ err = create_device(ctl, ncsk, nisk, subclass, nosdp, nocheck, bootonly, encrypt, timeout);
+ if (err < 0)
+ syslog(LOG_ERR, "HID create error %d (%s)",
+ errno, strerror(errno));
+
+ close(nisk);
+ sleep(1);
+ close(ncsk);
+ }
+ }
+}
+
+static char *hidp_state[] = {
+ "unknown",
+ "connected",
+ "open",
+ "bound",
+ "listening",
+ "connecting",
+ "connecting",
+ "config",
+ "disconnecting",
+ "closed"
+};
+
+static char *hidp_flagstostr(uint32_t flags)
+{
+ static char str[100];
+ str[0] = 0;
+
+ strcat(str, "[");
+
+ if (flags & (1 << HIDP_BOOT_PROTOCOL_MODE))
+ strcat(str, "boot-protocol");
+
+ strcat(str, "]");
+
+ return str;
+}
+
+static void do_show(int ctl)
+{
+ struct hidp_connlist_req req;
+ struct hidp_conninfo ci[16];
+ char addr[18];
+ int i;
+
+ req.cnum = 16;
+ req.ci = ci;
+
+ if (ioctl(ctl, HIDPGETCONNLIST, &req) < 0) {
+ perror("Can't get connection list");
+ close(ctl);
+ exit(1);
+ }
+
+ for (i = 0; i < req.cnum; i++) {
+ ba2str(&ci[i].bdaddr, addr);
+ printf("%s %s [%04x:%04x] %s %s\n", addr, ci[i].name,
+ ci[i].vendor, ci[i].product, hidp_state[ci[i].state],
+ ci[i].flags ? hidp_flagstostr(ci[i].flags) : "");
+ }
+}
+
+static void do_connect(int ctl, bdaddr_t *src, bdaddr_t *dst, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout)
+{
+ struct hidp_connadd_req req;
+ uint16_t uuid = HID_SVCLASS_ID;
+ uint8_t channel = 0;
+ char name[256];
+ int csk, isk, err;
+
+ memset(&req, 0, sizeof(req));
+
+ err = get_sdp_device_info(src, dst, &req);
+ if (err < 0 && fakehid)
+ err = get_alternate_device_info(src, dst,
+ &uuid, &channel, name, sizeof(name) - 1);
+
+ if (err < 0) {
+ perror("Can't get device information");
+ close(ctl);
+ exit(1);
+ }
+
+ switch (uuid) {
+ case HID_SVCLASS_ID:
+ goto connect;
+
+ case SERIAL_PORT_SVCLASS_ID:
+ if (subclass == 0x40 || !strcmp(name, "Cable Replacement")) {
+ if (epox_presenter(src, dst, channel) < 0) {
+ close(ctl);
+ exit(1);
+ }
+ break;
+ }
+ if (subclass == 0x1f || !strcmp(name, "SPP slave")) {
+ if (jthree_keyboard(src, dst, channel) < 0) {
+ close(ctl);
+ exit(1);
+ }
+ break;
+ }
+ if (subclass == 0x02 || !strcmp(name, "Serial Port")) {
+ if (celluon_keyboard(src, dst, channel) < 0) {
+ close(ctl);
+ exit(1);
+ }
+ break;
+ }
+ break;
+
+ case HEADSET_SVCLASS_ID:
+ case HANDSFREE_SVCLASS_ID:
+ if (headset_presenter(src, dst, channel) < 0) {
+ close(ctl);
+ exit(1);
+ }
+ break;
+ }
+
+ return;
+
+connect:
+ csk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_CTRL);
+ if (csk < 0) {
+ perror("Can't create HID control channel");
+ close(ctl);
+ exit(1);
+ }
+
+ isk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_INTR);
+ if (isk < 0) {
+ perror("Can't create HID interrupt channel");
+ close(csk);
+ close(ctl);
+ exit(1);
+ }
+
+ err = create_device(ctl, csk, isk, subclass, 1, 1, bootonly, encrypt, timeout);
+ if (err < 0) {
+ fprintf(stderr, "HID create error %d (%s)\n",
+ errno, strerror(errno));
+ close(isk);
+ sleep(1);
+ close(csk);
+ close(ctl);
+ exit(1);
+ }
+}
+
+static void do_search(int ctl, bdaddr_t *bdaddr, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout)
+{
+ inquiry_info *info = NULL;
+ bdaddr_t src, dst;
+ int i, dev_id, num_rsp, length, flags;
+ char addr[18];
+ uint8_t class[3];
+
+ ba2str(bdaddr, addr);
+ dev_id = hci_devid(addr);
+ if (dev_id < 0) {
+ dev_id = hci_get_route(NULL);
+ hci_devba(dev_id, &src);
+ } else
+ bacpy(&src, bdaddr);
+
+ length = 8; /* ~10 seconds */
+ num_rsp = 0;
+ flags = IREQ_CACHE_FLUSH;
+
+ printf("Searching ...\n");
+
+ num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags);
+
+ for (i = 0; i < num_rsp; i++) {
+ memcpy(class, (info+i)->dev_class, 3);
+ if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01)) {
+ bacpy(&dst, &(info+i)->bdaddr);
+ ba2str(&dst, addr);
+
+ printf("\tConnecting to device %s\n", addr);
+ do_connect(ctl, &src, &dst, subclass, fakehid, bootonly, encrypt, timeout);
+ }
+ }
+
+ if (!fakehid)
+ goto done;
+
+ for (i = 0; i < num_rsp; i++) {
+ memcpy(class, (info+i)->dev_class, 3);
+ if ((class[0] == 0x00 && class[2] == 0x00 &&
+ (class[1] == 0x40 || class[1] == 0x1f)) ||
+ (class[0] == 0x10 && class[1] == 0x02 && class[2] == 0x40)) {
+ bacpy(&dst, &(info+i)->bdaddr);
+ ba2str(&dst, addr);
+
+ printf("\tConnecting to device %s\n", addr);
+ do_connect(ctl, &src, &dst, subclass, 1, bootonly, 0, timeout);
+ }
+ }
+
+done:
+ bt_free(info);
+
+ if (!num_rsp) {
+ fprintf(stderr, "\tNo devices in range or visible\n");
+ close(ctl);
+ exit(1);
+ }
+}
+
+static void do_kill(int ctl, bdaddr_t *bdaddr, uint32_t flags)
+{
+ struct hidp_conndel_req req;
+ struct hidp_connlist_req cl;
+ struct hidp_conninfo ci[16];
+ int i;
+
+ if (!bacmp(bdaddr, BDADDR_ALL)) {
+ cl.cnum = 16;
+ cl.ci = ci;
+
+ if (ioctl(ctl, HIDPGETCONNLIST, &cl) < 0) {
+ perror("Can't get connection list");
+ close(ctl);
+ exit(1);
+ }
+
+ for (i = 0; i < cl.cnum; i++) {
+ bacpy(&req.bdaddr, &ci[i].bdaddr);
+ req.flags = flags;
+
+ if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
+ perror("Can't release connection");
+ close(ctl);
+ exit(1);
+ }
+ }
+
+ } else {
+ bacpy(&req.bdaddr, bdaddr);
+ req.flags = flags;
+
+ if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
+ perror("Can't release connection");
+ close(ctl);
+ exit(1);
+ }
+ }
+}
+
+static void usage(void)
+{
+ printf("hidd - Bluetooth HID daemon version %s\n\n", VERSION);
+
+ printf("Usage:\n"
+ "\thidd [options] [commands]\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-i <hciX|bdaddr> Local HCI device or BD Address\n"
+ "\t-t <timeout> Set idle timeout (in minutes)\n"
+ "\t-b <subclass> Overwrite the boot mode subclass\n"
+ "\t-n, --nodaemon Don't fork daemon to background\n"
+ "\t-h, --help Display help\n"
+ "\n");
+
+ printf("Commands:\n"
+ "\t--server Start HID server\n"
+ "\t--search Search for HID devices\n"
+ "\t--connect <bdaddr> Connect remote HID device\n"
+ "\t--unplug <bdaddr> Unplug the HID connection\n"
+ "\t--kill <bdaddr> Terminate HID connection\n"
+ "\t--killall Terminate all connections\n"
+ "\t--show List current HID connections\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "nodaemon", 0, 0, 'n' },
+ { "subclass", 1, 0, 'b' },
+ { "timeout", 1, 0, 't' },
+ { "device", 1, 0, 'i' },
+ { "master", 0, 0, 'M' },
+ { "encrypt", 0, 0, 'E' },
+ { "nosdp", 0, 0, 'D' },
+ { "nocheck", 0, 0, 'Z' },
+ { "bootonly", 0, 0, 'B' },
+ { "hidonly", 0, 0, 'H' },
+ { "show", 0, 0, 'l' },
+ { "list", 0, 0, 'l' },
+ { "server", 0, 0, 'd' },
+ { "listen", 0, 0, 'd' },
+ { "search", 0, 0, 's' },
+ { "create", 1, 0, 'c' },
+ { "connect", 1, 0, 'c' },
+ { "disconnect", 1, 0, 'k' },
+ { "terminate", 1, 0, 'k' },
+ { "release", 1, 0, 'k' },
+ { "kill", 1, 0, 'k' },
+ { "killall", 0, 0, 'K' },
+ { "unplug", 1, 0, 'u' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ bdaddr_t bdaddr, dev;
+ uint32_t flags = 0;
+ uint8_t subclass = 0x00;
+ char addr[18];
+ int log_option = LOG_NDELAY | LOG_PID;
+ int opt, ctl, csk, isk;
+ int mode = SHOW, detach = 1, nosdp = 0, nocheck = 0, bootonly = 0;
+ int fakehid = 1, encrypt = 0, timeout = 30, lm = 0;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt = getopt_long(argc, argv, "+i:nt:b:MEDZBHldsc:k:Ku:h", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'i':
+ if (!strncasecmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &bdaddr);
+ else
+ str2ba(optarg, &bdaddr);
+ break;
+ case 'n':
+ detach = 0;
+ break;
+ case 't':
+ timeout = atoi(optarg);
+ break;
+ case 'b':
+ if (!strncasecmp(optarg, "0x", 2))
+ subclass = (uint8_t) strtol(optarg, NULL, 16);
+ else
+ subclass = atoi(optarg);
+ break;
+ case 'M':
+ lm |= L2CAP_LM_MASTER;
+ break;
+ case 'E':
+ encrypt = 1;
+ break;
+ case 'D':
+ nosdp = 1;
+ break;
+ case 'Z':
+ nocheck = 1;
+ break;
+ case 'B':
+ bootonly = 1;
+ break;
+ case 'H':
+ fakehid = 0;
+ break;
+ case 'l':
+ mode = SHOW;
+ break;
+ case 'd':
+ mode = SERVER;
+ break;
+ case 's':
+ mode = SEARCH;
+ break;
+ case 'c':
+ str2ba(optarg, &dev);
+ mode = CONNECT;
+ break;
+ case 'k':
+ str2ba(optarg, &dev);
+ mode = KILL;
+ break;
+ case 'K':
+ bacpy(&dev, BDADDR_ALL);
+ mode = KILL;
+ break;
+ case 'u':
+ str2ba(optarg, &dev);
+ flags = (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
+ mode = KILL;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ exit(0);
+ }
+ }
+
+ ba2str(&bdaddr, addr);
+
+ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+ if (ctl < 0) {
+ perror("Can't open HIDP control socket");
+ exit(1);
+ }
+
+ switch (mode) {
+ case SERVER:
+ csk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_CTRL, lm, 10);
+ if (csk < 0) {
+ perror("Can't listen on HID control channel");
+ close(ctl);
+ exit(1);
+ }
+
+ isk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_INTR, lm, 10);
+ if (isk < 0) {
+ perror("Can't listen on HID interrupt channel");
+ close(ctl);
+ close(csk);
+ exit(1);
+ }
+ break;
+
+ case SEARCH:
+ do_search(ctl, &bdaddr, subclass, fakehid, bootonly, encrypt, timeout);
+ close(ctl);
+ exit(0);
+
+ case CONNECT:
+ do_connect(ctl, &bdaddr, &dev, subclass, fakehid, bootonly, encrypt, timeout);
+ close(ctl);
+ exit(0);
+
+ case KILL:
+ do_kill(ctl, &dev, flags);
+ close(ctl);
+ exit(0);
+
+ default:
+ do_show(ctl);
+ close(ctl);
+ exit(0);
+ }
+
+ if (detach) {
+ if (daemon(0, 0)) {
+ perror("Can't start daemon");
+ exit(1);
+ }
+ } else
+ log_option |= LOG_PERROR;
+
+ openlog("hidd", log_option, LOG_DAEMON);
+
+ if (bacmp(&bdaddr, BDADDR_ANY))
+ syslog(LOG_INFO, "Bluetooth HID daemon (%s)", addr);
+ else
+ syslog(LOG_INFO, "Bluetooth HID daemon");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ run_server(ctl, csk, isk, subclass, nosdp, nocheck, bootonly, encrypt, timeout);
+
+ syslog(LOG_INFO, "Exit");
+
+ close(csk);
+ close(isk);
+ close(ctl);
+
+ return 0;
+}
diff --git a/utils/hidd/sdp.c b/utils/hidd/sdp.c
new file mode 100644
index 00000000..eaf8c136
--- /dev/null
+++ b/utils/hidd/sdp.c
@@ -0,0 +1,352 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/hidp.h>
+
+#include "textfile.h"
+#include "hidd.h"
+
+static void epox_endian_quirk(unsigned char *data, int size)
+{
+ /* USAGE_PAGE (Keyboard) 05 07
+ * USAGE_MINIMUM (0) 19 00
+ * USAGE_MAXIMUM (65280) 2A 00 FF <= must be FF 00
+ * LOGICAL_MINIMUM (0) 15 00
+ * LOGICAL_MAXIMUM (65280) 26 00 FF <= must be FF 00
+ */
+ unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff,
+ 0x15, 0x00, 0x26, 0x00, 0xff };
+ int i;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < size - sizeof(pattern); i++) {
+ if (!memcmp(data + i, pattern, sizeof(pattern))) {
+ data[i + 5] = 0xff;
+ data[i + 6] = 0x00;
+ data[i + 10] = 0xff;
+ data[i + 11] = 0x00;
+ }
+ }
+}
+
+static int store_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
+{
+ char filename[PATH_MAX + 1], addr[18], *str, *desc;
+ int i, err, size;
+
+ ba2str(src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd");
+
+ size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2;
+ str = malloc(size);
+ if (!str)
+ return -ENOMEM;
+
+ desc = malloc((req->rd_size * 2) + 1);
+ if (!desc) {
+ free(str);
+ return -ENOMEM;
+ }
+
+ memset(desc, 0, (req->rd_size * 2) + 1);
+ for (i = 0; i < req->rd_size; i++)
+ sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]);
+
+ snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s",
+ req->vendor, req->product, req->version,
+ req->subclass, req->country, req->parser, desc,
+ req->flags, req->name);
+
+ free(desc);
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(dst, addr);
+ err = textfile_put(filename, addr, str);
+
+ free(str);
+
+ return err;
+}
+
+int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
+{
+ char filename[PATH_MAX + 1], addr[18], tmp[3], *str, *desc;
+ unsigned int vendor, product, version, subclass, country, parser, pos;
+ int i;
+
+ desc = malloc(4096);
+ if (!desc)
+ return -ENOMEM;
+
+ memset(desc, 0, 4096);
+
+ ba2str(src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd");
+
+ ba2str(dst, addr);
+ str = textfile_get(filename, addr);
+ if (!str) {
+ free(desc);
+ return -EIO;
+ }
+
+ sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n",
+ &vendor, &product, &version, &subclass, &country,
+ &parser, desc, &req->flags, &pos);
+
+ free(str);
+
+ req->vendor = vendor;
+ req->product = product;
+ req->version = version;
+ req->subclass = subclass;
+ req->country = country;
+ req->parser = parser;
+
+ snprintf(req->name, 128, str + pos);
+
+ req->rd_size = strlen(desc) / 2;
+ req->rd_data = malloc(req->rd_size);
+ if (!req->rd_data) {
+ free(desc);
+ return -ENOMEM;
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < req->rd_size; i++) {
+ memcpy(tmp, desc + (i * 2), 2);
+ req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ free(desc);
+
+ return 0;
+}
+
+int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
+{
+ struct sockaddr_l2 addr;
+ socklen_t addrlen;
+ bdaddr_t bdaddr;
+ uint32_t range = 0x0000ffff;
+ sdp_session_t *s;
+ sdp_list_t *search, *attrid, *pnp_rsp, *hid_rsp;
+ sdp_record_t *rec;
+ sdp_data_t *pdlist, *pdlist2;
+ uuid_t svclass;
+ int err;
+
+ s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE);
+ if (!s)
+ return -1;
+
+ sdp_uuid16_create(&svclass, PNP_INFO_SVCLASS_ID);
+ search = sdp_list_append(NULL, &svclass);
+ attrid = sdp_list_append(NULL, &range);
+
+ err = sdp_service_search_attr_req(s, search,
+ SDP_ATTR_REQ_RANGE, attrid, &pnp_rsp);
+
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrid, NULL);
+
+ sdp_uuid16_create(&svclass, HID_SVCLASS_ID);
+ search = sdp_list_append(NULL, &svclass);
+ attrid = sdp_list_append(NULL, &range);
+
+ err = sdp_service_search_attr_req(s, search,
+ SDP_ATTR_REQ_RANGE, attrid, &hid_rsp);
+
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrid, NULL);
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+
+ if (getsockname(s->sock, (struct sockaddr *) &addr, &addrlen) < 0)
+ bacpy(&bdaddr, src);
+ else
+ bacpy(&bdaddr, &addr.l2_bdaddr);
+
+ sdp_close(s);
+
+ if (err || !hid_rsp)
+ return -1;
+
+ if (pnp_rsp) {
+ rec = (sdp_record_t *) pnp_rsp->data;
+
+ pdlist = sdp_data_get(rec, 0x0201);
+ req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, 0x0202);
+ req->product = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, 0x0203);
+ req->version = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ sdp_record_free(rec);
+ }
+
+ rec = (sdp_record_t *) hid_rsp->data;
+
+ pdlist = sdp_data_get(rec, 0x0101);
+ pdlist2 = sdp_data_get(rec, 0x0102);
+ if (pdlist) {
+ if (pdlist2) {
+ if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {
+ strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1);
+ strcat(req->name, " ");
+ }
+ strncat(req->name, pdlist->val.str,
+ sizeof(req->name) - strlen(req->name));
+ } else
+ strncpy(req->name, pdlist->val.str, sizeof(req->name));
+ } else {
+ pdlist2 = sdp_data_get(rec, 0x0100);
+ if (pdlist2)
+ strncpy(req->name, pdlist2->val.str, sizeof(req->name));
+ }
+
+ pdlist = sdp_data_get(rec, 0x0201);
+ req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
+
+ pdlist = sdp_data_get(rec, 0x0202);
+ req->subclass = pdlist ? pdlist->val.uint8 : 0;
+
+ pdlist = sdp_data_get(rec, 0x0203);
+ req->country = pdlist ? pdlist->val.uint8 : 0;
+
+ pdlist = sdp_data_get(rec, 0x0206);
+ if (pdlist) {
+ pdlist = pdlist->val.dataseq;
+ pdlist = pdlist->val.dataseq;
+ pdlist = pdlist->next;
+
+ req->rd_data = malloc(pdlist->unitSize);
+ if (req->rd_data) {
+ memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize);
+ req->rd_size = pdlist->unitSize;
+ epox_endian_quirk(req->rd_data, req->rd_size);
+ }
+ }
+
+ sdp_record_free(rec);
+
+ if (bacmp(&bdaddr, BDADDR_ANY))
+ store_device_info(&bdaddr, dst, req);
+
+ return 0;
+}
+
+int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len)
+{
+ uint16_t attr1 = SDP_ATTR_PROTO_DESC_LIST;
+ uint16_t attr2 = SDP_ATTR_SVCNAME_PRIMARY;
+ sdp_session_t *s;
+ sdp_list_t *search, *attrid, *rsp;
+ uuid_t svclass;
+ int err;
+
+ s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE);
+ if (!s)
+ return -1;
+
+ sdp_uuid16_create(&svclass, HEADSET_SVCLASS_ID);
+ search = sdp_list_append(NULL, &svclass);
+ attrid = sdp_list_append(NULL, &attr1);
+ attrid = sdp_list_append(attrid, &attr2);
+
+ err = sdp_service_search_attr_req(s, search,
+ SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp);
+
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrid, NULL);
+
+ if (err <= 0) {
+ sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
+ search = sdp_list_append(NULL, &svclass);
+ attrid = sdp_list_append(NULL, &attr1);
+ attrid = sdp_list_append(attrid, &attr2);
+
+ err = sdp_service_search_attr_req(s, search,
+ SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp);
+
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrid, NULL);
+
+ if (err < 0) {
+ sdp_close(s);
+ return err;
+ }
+
+ if (uuid)
+ *uuid = SERIAL_PORT_SVCLASS_ID;
+ } else {
+ if (uuid)
+ *uuid = HEADSET_SVCLASS_ID;
+ }
+
+ sdp_close(s);
+
+ for (; rsp; rsp = rsp->next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
+ sdp_list_t *protos;
+
+ sdp_get_service_name(rec, name, len);
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ if (ch > 0) {
+ if (channel)
+ *channel = ch;
+ return 0;
+ }
+ }
+
+ sdp_record_free(rec);
+ }
+
+ return -EIO;
+}
diff --git a/utils/input/Makefile.am b/utils/input/Makefile.am
new file mode 100644
index 00000000..1bc81fbe
--- /dev/null
+++ b/utils/input/Makefile.am
@@ -0,0 +1,24 @@
+
+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 \
+ storage.h storage.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 \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid
+
+EXTRA_DIST = input.conf input-api.txt test-input
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/input/Makefile.in b/utils/input/Makefile.in
new file mode 100644
index 00000000..47d441dd
--- /dev/null
+++ b/utils/input/Makefile.in
@@ -0,0 +1,508 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = input
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(plugindir)"
+pluginLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+input_la_LIBADD =
+am__input_la_SOURCES_DIST = main.c manager.h manager.c server.h \
+ server.c device.h device.c storage.h storage.c fakehid.c \
+ fakehid.h
+@INPUTPLUGIN_TRUE@am_input_la_OBJECTS = main.lo manager.lo server.lo \
+@INPUTPLUGIN_TRUE@ device.lo storage.lo fakehid.lo
+input_la_OBJECTS = $(am_input_la_OBJECTS)
+@INPUTPLUGIN_TRUE@am_input_la_rpath = -rpath $(plugindir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(input_la_SOURCES)
+DIST_SOURCES = $(am__input_la_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@INPUTPLUGIN_TRUE@plugindir = $(libdir)/bluetooth/plugins
+@INPUTPLUGIN_TRUE@plugin_LTLIBRARIES = input.la
+@INPUTPLUGIN_TRUE@input_la_SOURCES = main.c manager.h manager.c \
+@INPUTPLUGIN_TRUE@ server.h server.c device.h device.c \
+@INPUTPLUGIN_TRUE@ storage.h storage.c fakehid.c fakehid.h
+
+@INPUTPLUGIN_TRUE@LDADD = $(top_builddir)/common/libhelper.a \
+@INPUTPLUGIN_TRUE@ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+AM_LDFLAGS = -module -avoid-version -no-undefined \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid
+EXTRA_DIST = input.conf input-api.txt test-input
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu input/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu input/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+input.la: $(input_la_OBJECTS) $(input_la_DEPENDENCIES)
+ $(LINK) $(am_input_la_rpath) $(input_la_OBJECTS) $(input_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fakehid.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/input/device.c b/utils/input/device.c
new file mode 100644
index 00000000..75acaa82
--- /dev/null
+++ b/utils/input/device.c
@@ -0,0 +1,1171 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hidp.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "logging.h"
+#include "textfile.h"
+#include "uinput.h"
+
+#include "device.h"
+#include "error.h"
+#include "manager.h"
+#include "storage.h"
+#include "fakehid.h"
+#include "glib-helper.h"
+
+#define INPUT_DEVICE_INTERFACE "org.bluez.input.Device"
+
+#define BUF_SIZE 16
+
+#define UPDOWN_ENABLED 1
+
+#define FI_FLAG_CONNECTED 1
+
+struct device;
+
+struct device {
+ bdaddr_t src;
+ bdaddr_t dst;
+ int timeout;
+ char *name;
+ uint8_t major;
+ uint8_t minor;
+ uint16_t product;
+ uint16_t vendor;
+ struct fake_input *fake;
+ DBusMessage *pending_connect;
+ DBusConnection *conn;
+ char *path;
+ int ctrl_sk;
+ int intr_sk;
+ guint ctrl_watch;
+ guint intr_watch;
+};
+
+GSList *devices = NULL;
+
+static struct device *device_new(bdaddr_t *src, bdaddr_t *dst,
+ uint8_t subclass, int timeout)
+{
+ struct device *idev;
+ uint32_t cls;
+ uint8_t major, minor;
+
+ if (!subclass) {
+ if (read_device_class(src, dst, &cls) < 0)
+ return NULL;
+
+ major = (cls >> 8) & 0x1f;
+ minor = (cls >> 2) & 0x3f;
+ } else {
+ major = 0x05; /* Peripheral */
+ minor = (subclass >> 2) & 0x3f;
+ }
+
+ idev = g_new0(struct device, 1);
+
+ bacpy(&idev->src, src);
+ bacpy(&idev->dst, dst);
+ idev->timeout = timeout;
+
+ read_device_name(src, dst, &idev->name);
+
+ idev->major = major;
+ idev->minor = minor;
+ idev->ctrl_sk = -1;
+ idev->intr_sk = -1;
+
+ return idev;
+}
+
+static void device_free(struct device *idev)
+{
+ if (!idev)
+ return;
+ if (idev->name)
+ g_free(idev->name);
+ if (idev->fake)
+ g_free(idev->fake);
+ if (idev->path)
+ g_free(idev->path);
+ if (idev->pending_connect)
+ dbus_message_unref(idev->pending_connect);
+ dbus_connection_unref(idev->conn);
+ g_free(idev);
+}
+
+static int uinput_create(char *name)
+{
+ struct uinput_dev dev;
+ int fd, err;
+
+ fd = open("/dev/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/input/uinput", O_RDWR);
+ if (fd < 0) {
+ fd = open("/dev/misc/uinput", O_RDWR);
+ if (fd < 0) {
+ err = errno;
+ error("Can't open input device: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+ }
+ }
+
+ memset(&dev, 0, sizeof(dev));
+ if (name)
+ strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
+
+ dev.id.bustype = BUS_BLUETOOTH;
+ dev.id.vendor = 0x0000;
+ dev.id.product = 0x0000;
+ dev.id.version = 0x0000;
+
+ if (write(fd, &dev, sizeof(dev)) < 0) {
+ err = errno;
+ error("Can't write device information: %s (%d)",
+ strerror(err), err);
+ close(fd);
+ errno = err;
+ return -err;
+ }
+
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+ ioctl(fd, UI_SET_EVBIT, EV_REP);
+
+ ioctl(fd, UI_SET_KEYBIT, KEY_UP);
+ ioctl(fd, UI_SET_KEYBIT, KEY_PAGEUP);
+ ioctl(fd, UI_SET_KEYBIT, KEY_DOWN);
+ ioctl(fd, UI_SET_KEYBIT, KEY_PAGEDOWN);
+
+ if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+ err = errno;
+ error("Can't create uinput device: %s (%d)",
+ strerror(err), err);
+ close(fd);
+ errno = err;
+ return -err;
+ }
+
+ return fd;
+}
+
+static const char *create_input_path(uint8_t major, uint8_t minor)
+{
+ static char path[48];
+ char subpath[32];
+ static int next_id = 0;
+
+ switch (major) {
+ case 0x02: /* Phone */
+ strcpy(subpath, "phone");
+ break;
+ case 0x04: /* Audio */
+ switch (minor) {
+ /* FIXME: Testing required */
+ case 0x01: /* Wearable Headset Device */
+ strcpy(subpath, "wearable");
+ break;
+ case 0x02: /* Hands-free */
+ strcpy(subpath, "handsfree");
+ break;
+ case 0x06: /* Headphone */
+ strcpy(subpath, "headphone");
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ case 0x05: /* Peripheral */
+ switch (minor & 0x30) {
+ case 0x10:
+ strcpy(subpath, "keyboard");
+ break;
+ case 0x20:
+ strcpy(subpath, "pointing");
+ break;
+ case 0x30:
+ strcpy(subpath, "combo");
+ break;
+ default:
+ subpath[0] = '\0';
+ break;
+ }
+
+ if ((minor & 0x0f) && (strlen(subpath) > 0))
+ strcat(subpath, "/");
+
+ switch (minor & 0x0f) {
+ case 0x00:
+ break;
+ case 0x01:
+ strcat(subpath, "joystick");
+ break;
+ case 0x02:
+ strcat(subpath, "gamepad");
+ break;
+ case 0x03:
+ strcat(subpath, "remotecontrol");
+ break;
+ case 0x04:
+ strcat(subpath, "sensing");
+ break;
+ case 0x05:
+ strcat(subpath, "digitizertablet");
+ break;
+ case 0x06:
+ strcat(subpath, "cardreader");
+ break;
+ default:
+ strcat(subpath, "reserved");
+ break;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ snprintf(path, 48, "%s/%s%d", INPUT_PATH, subpath, next_id++);
+ return path;
+}
+
+static int decode_key(const char *str)
+{
+ static int mode = UPDOWN_ENABLED, gain = 0;
+
+ uint16_t key;
+ int new_gain;
+
+ /* Switch from key up/down to page up/down */
+ if (strncmp("AT+CKPD=200", str, 11) == 0) {
+ mode = ~mode;
+ return KEY_RESERVED;
+ }
+
+ if (strncmp("AT+VG", str, 5))
+ return KEY_RESERVED;
+
+ /* Gain key pressed */
+ if (strlen(str) != 10)
+ return KEY_RESERVED;
+
+ new_gain = strtol(&str[7], NULL, 10);
+ if (new_gain <= gain)
+ key = (mode == UPDOWN_ENABLED ? KEY_UP : KEY_PAGEUP);
+ else
+ key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN);
+
+ gain = new_gain;
+
+ return key;
+}
+
+static void send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct uinput_event event;
+ int err;
+
+ memset(&event, 0, sizeof(event));
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ err = write(fd, &event, sizeof(event));
+}
+
+static void send_key(int fd, uint16_t key)
+{
+ /* Key press */
+ send_event(fd, EV_KEY, key, 1);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ /* Key release */
+ send_event(fd, EV_KEY, key, 0);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct fake_input *fake = data;
+ const char *ok = "\r\nOK\r\n";
+ char buf[BUF_SIZE];
+ gsize bread = 0, bwritten;
+ uint16_t key;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ error("Hangup or error on rfcomm server socket");
+ goto failed;
+ }
+
+ memset(buf, 0, BUF_SIZE);
+ if (g_io_channel_read(chan, buf, sizeof(buf) - 1,
+ &bread) != G_IO_ERROR_NONE) {
+ error("IO Channel read error");
+ goto failed;
+ }
+
+ debug("Received: %s", buf);
+
+ if (g_io_channel_write(chan, ok, 6, &bwritten) != G_IO_ERROR_NONE) {
+ error("IO Channel write error");
+ goto failed;
+ }
+
+ key = decode_key(buf);
+ if (key != KEY_RESERVED)
+ send_key(fake->uinput, key);
+
+ return TRUE;
+
+failed:
+ ioctl(fake->uinput, UI_DEV_DESTROY);
+ close(fake->uinput);
+ fake->uinput = -1;
+ g_io_channel_unref(fake->io);
+
+ return FALSE;
+}
+
+static inline DBusMessage *in_progress(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",
+ "Device connection already in progress");
+}
+
+static inline DBusMessage *already_connected(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected",
+ "Already connected to a device");
+}
+
+static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed",
+ err ? strerror(err) : "Connection attempt failed");
+}
+
+static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct device *idev = user_data;
+ struct fake_input *fake;
+ DBusMessage *reply;
+ const char *path;
+
+ fake = idev->fake;
+ fake->rfcomm = g_io_channel_unix_get_fd(chan);
+
+ if (err < 0)
+ goto failed;
+
+ /*
+ * FIXME: Some headsets required a sco connection
+ * first to report volume gain key events
+ */
+ fake->uinput = uinput_create(idev->name);
+ if (fake->uinput < 0) {
+ err = errno;
+ goto failed;
+ }
+
+ fake->io = g_io_channel_unix_new(fake->rfcomm);
+ g_io_channel_set_close_on_unref(fake->io, TRUE);
+ g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) rfcomm_io_cb, fake);
+
+ /* Replying to the requestor */
+ reply = dbus_message_new_method_return(idev->pending_connect);
+ g_dbus_send_message(idev->conn, reply);
+
+ /* Sending the Connected signal */
+ path = dbus_message_get_path(idev->pending_connect);
+ g_dbus_emit_signal(idev->conn, path,
+ INPUT_DEVICE_INTERFACE, "Connected",
+ DBUS_TYPE_INVALID);
+
+ dbus_message_unref(idev->pending_connect);
+ idev->pending_connect = NULL;
+
+ return;
+
+failed:
+ reply = connection_attempt_failed(idev->pending_connect, err);
+ g_dbus_send_message(idev->conn, reply);
+
+ dbus_message_unref(idev->pending_connect);
+ idev->pending_connect = NULL;
+}
+
+static int rfcomm_connect(struct device *idev)
+{
+ int err;
+
+ err = bt_rfcomm_connect(&idev->src, &idev->dst, idev->fake->ch,
+ rfcomm_connect_cb, idev);
+ if (err < 0) {
+ error("connect() failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ return 0;
+}
+
+static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct device *idev = data;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ g_io_channel_close(chan);
+
+ g_dbus_emit_signal(idev->conn,
+ idev->path,
+ INPUT_DEVICE_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+
+ g_source_remove(idev->ctrl_watch);
+ idev->ctrl_watch = 0;
+ idev->intr_watch = 0;
+
+ /* Close control channel */
+ if (idev->ctrl_sk > 0) {
+ close(idev->ctrl_sk);
+ idev->ctrl_sk = -1;
+ }
+
+ return FALSE;
+
+}
+
+static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct device *idev = data;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ g_io_channel_close(chan);
+
+ g_dbus_emit_signal(idev->conn,
+ idev->path,
+ INPUT_DEVICE_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+
+ g_source_remove(idev->intr_watch);
+ idev->intr_watch = 0;
+ idev->ctrl_watch = 0;
+
+ /* Close interrupt channel */
+ if (idev->intr_sk > 0) {
+ close(idev->intr_sk);
+ idev->intr_sk = -1;
+ }
+
+ return FALSE;
+}
+
+static guint create_watch(int sk, GIOFunc cb, struct device *idev)
+{
+ guint id;
+ GIOChannel *io;
+
+ io = g_io_channel_unix_new(sk);
+ id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, cb, idev);
+ g_io_channel_unref(io);
+
+ return id;
+}
+
+static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst,
+ int ctrl_sk, int intr_sk, int timeout, const char *name)
+{
+ struct hidp_connadd_req req;
+ char addr[18];
+ int ctl, err;
+
+ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+ if (ctl < 0) {
+ error("Can't open HIDP interface");
+ return -errno;
+ }
+
+ ba2str(dst, addr);
+
+ memset(&req, 0, sizeof(req));
+ req.ctrl_sock = ctrl_sk;
+ req.intr_sock = intr_sk;
+ req.flags = 0;
+ req.idle_to = timeout;
+
+ err = get_stored_device_info(src, dst, &req);
+ if (err < 0) {
+ error("Rejected connection from unknown device %s", addr);
+ goto cleanup;
+ }
+
+ if (req.subclass & 0x40) {
+ err = encrypt_link(src, dst);
+ if (err < 0 && err != -EACCES)
+ goto cleanup;
+ }
+
+ if (name)
+ strncpy(req.name, name, 128);
+
+ info("New input device %s (%s)", addr, req.name);
+
+ if (req.vendor == 0x054c && req.product == 0x0268) {
+ unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 };
+ err = write(ctrl_sk, buf, sizeof(buf));
+ }
+
+ err = ioctl(ctl, HIDPCONNADD, &req);
+
+cleanup:
+ close(ctl);
+
+ if (req.rd_data)
+ free(req.rd_data);
+
+ return err;
+}
+
+static void interrupt_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct device *idev = user_data;
+ DBusMessage *reply;
+
+ if (err < 0) {
+ error("connect(): %s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ idev->intr_sk = g_io_channel_unix_get_fd(chan);
+ err = hidp_connadd(&idev->src, &idev->dst,
+ idev->ctrl_sk, idev->intr_sk,
+ idev->timeout, idev->name);
+ if (err < 0)
+ goto failed;
+
+ idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev);
+ idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev);
+ g_dbus_emit_signal(idev->conn,
+ idev->path,
+ INPUT_DEVICE_INTERFACE,
+ "Connected",
+ DBUS_TYPE_INVALID);
+
+ /* Replying to the requestor */
+ g_dbus_send_reply(idev->conn, idev->pending_connect, DBUS_TYPE_INVALID);
+
+ goto cleanup;
+
+failed:
+ reply = connection_attempt_failed(idev->pending_connect, -err);
+ g_dbus_send_message(idev->conn, reply);
+
+ idev->intr_sk = -1;
+ idev->ctrl_sk = -1;
+
+cleanup:
+ dbus_message_unref(idev->pending_connect);
+ idev->pending_connect = NULL;
+}
+
+static void control_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct device *idev = user_data;
+
+ if (err < 0) {
+ error("connect(): %s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ /* Set HID control channel */
+ idev->ctrl_sk = g_io_channel_unix_get_fd(chan);
+
+ /* Connect to the HID interrupt channel */
+ err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, 0,
+ interrupt_connect_cb, idev);
+ if (err < 0) {
+ error("L2CAP connect failed:%s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ idev->ctrl_sk = -1;
+ error_connection_attempt_failed(idev->conn,
+ idev->pending_connect, -err);
+ dbus_message_unref(idev->pending_connect);
+ idev->pending_connect = NULL;
+}
+
+static int fake_disconnect(struct device *idev)
+{
+ struct fake_input *fake = idev->fake;
+
+ if (!fake->io)
+ return -ENOTCONN;
+
+ g_io_channel_close(fake->io);
+ g_io_channel_unref(fake->io);
+ fake->io = NULL;
+
+ if (fake->uinput >= 0) {
+ ioctl(fake->uinput, UI_DEV_DESTROY);
+ close(fake->uinput);
+ fake->uinput = -1;
+ }
+
+ return 0;
+}
+
+static int disconnect(struct device *idev, uint32_t flags)
+{
+ struct fake_input *fake = idev->fake;
+ struct hidp_conndel_req req;
+ struct hidp_conninfo ci;
+ int ctl, err;
+
+ /* Fake input disconnect */
+ if (fake) {
+ err = fake->disconnect(idev);
+ if (err == 0)
+ fake->flags &= ~FI_FLAG_CONNECTED;
+ return err;
+ }
+
+ /* Standard HID disconnect */
+ if (idev->ctrl_sk >= 0) {
+ close(idev->ctrl_sk);
+ idev->ctrl_sk = -1;
+ }
+ if (idev->intr_sk >= 0) {
+ close(idev->intr_sk);
+ idev->intr_sk = -1;
+ }
+
+ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+ if (ctl < 0) {
+ error("Can't open HIDP control socket");
+ return -errno;
+ }
+
+ memset(&ci, 0, sizeof(ci));
+ bacpy(&ci.bdaddr, &idev->dst);
+ if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) ||
+ (ci.state != BT_CONNECTED)) {
+ errno = ENOTCONN;
+ goto fail;
+ }
+
+ memset(&req, 0, sizeof(req));
+ bacpy(&req.bdaddr, &idev->dst);
+ req.flags = flags;
+ if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
+ error("Can't delete the HID device: %s(%d)",
+ strerror(errno), errno);
+ goto fail;
+ }
+
+ close(ctl);
+
+ return 0;
+
+fail:
+ err = errno;
+ close(ctl);
+ errno = err;
+
+ return -err;
+}
+
+static int is_connected(struct device *idev)
+{
+ struct fake_input *fake = idev->fake;
+ struct hidp_conninfo ci;
+ int ctl;
+
+ /* Fake input */
+ if (fake)
+ return fake->flags & FI_FLAG_CONNECTED;
+
+ /* Standard HID */
+ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+ if (ctl < 0)
+ return 0;
+
+ memset(&ci, 0, sizeof(ci));
+ bacpy(&ci.bdaddr, &idev->dst);
+ if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) {
+ close(ctl);
+ return 0;
+ }
+
+ close(ctl);
+
+ if (ci.state != BT_CONNECTED)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * Input Device methods
+ */
+static DBusMessage *device_connect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+ struct fake_input *fake = idev->fake;
+ int err;
+
+ if (idev->pending_connect)
+ return in_progress(msg);
+
+ if (is_connected(idev))
+ return already_connected(msg);
+
+ idev->pending_connect = dbus_message_ref(msg);
+
+ /* Fake input device */
+ if (fake) {
+ if (fake->connect(idev) < 0) {
+ int err = errno;
+ const char *str = strerror(err);
+ error("Connect failed: %s(%d)", str, err);
+ dbus_message_unref(idev->pending_connect);
+ idev->pending_connect = NULL;
+ return connection_attempt_failed(msg, err);
+ }
+ fake->flags |= FI_FLAG_CONNECTED;
+ return NULL;
+ }
+
+ /* HID devices */
+ err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL,
+ 0, control_connect_cb, idev);
+ if (err < 0) {
+ error("L2CAP connect failed: %s(%d)", strerror(-err), -err);
+ dbus_message_unref(idev->pending_connect);
+ idev->pending_connect = NULL;
+ return connection_attempt_failed(msg, -err);
+ }
+
+ return NULL;
+}
+
+static DBusMessage *device_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+ int err;
+
+ err = disconnect(idev, 0);
+ if (err < 0)
+ return create_errno_message(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *device_is_connected(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+ dbus_bool_t connected = is_connected(idev);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_BOOLEAN, &connected,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *device_get_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+ char addr[18];
+ const char *paddr = addr;
+
+ ba2str(&idev->src, addr);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *device_get_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+ char addr[18];
+ const char *paddr = addr;
+
+ ba2str(&idev->dst, addr);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *device_get_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+ const char *pname = (idev->name ? idev->name : "");
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &pname,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *device_get_product_id(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->product,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *device_get_vendor_id(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *idev = data;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_UINT16, &idev->vendor,
+ DBUS_TYPE_INVALID);
+}
+
+static void device_unregister(void *data)
+{
+ struct device *idev = data;
+
+ /* Disconnect if applied */
+ disconnect(idev, (1 << HIDP_VIRTUAL_CABLE_UNPLUG));
+ device_free(idev);
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "Connect", "", "", device_connect,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "Disconnect", "", "", device_disconnect },
+ { "IsConnected", "", "b", device_is_connected },
+ { "GetAdapter", "", "s", device_get_adapter },
+ { "GetAddress", "", "s", device_get_address },
+ { "GetName", "", "s", device_get_name },
+ { "GetProductId", "", "q", device_get_product_id },
+ { "GetVendorId", "", "q", device_get_vendor_id },
+ { }
+};
+
+static GDBusSignalTable device_signals[] = {
+ { "Connected", "" },
+ { "Disconnected", "" },
+ { }
+};
+
+/*
+ * Input registration functions
+ */
+static int register_path(DBusConnection *conn, const char *path, struct device *idev)
+{
+ if (g_dbus_register_interface(conn, path, INPUT_DEVICE_INTERFACE,
+ device_methods, device_signals, NULL,
+ idev, device_unregister) == FALSE) {
+ error("Failed to register %s interface to %s",
+ INPUT_DEVICE_INTERFACE, path);
+ return -1;
+ }
+
+ devices = g_slist_append(devices, idev);
+
+ info("Created input device: %s", path);
+
+ return 0;
+}
+
+int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
+ struct hidp_connadd_req *hid, const char **ppath)
+{
+ struct device *idev;
+ const char *path;
+ int err;
+
+ idev = device_new(src, dst, hid->subclass, hid->idle_to);
+ if (!idev)
+ return -EINVAL;
+
+ path = create_input_path(idev->major, idev->minor);
+ if (!path) {
+ device_free(idev);
+ return -EINVAL;
+ }
+
+ idev->path = g_strdup(path);
+ idev->product = hid->product;
+ idev->vendor = hid->vendor;
+ idev->conn = dbus_connection_ref(conn);
+
+ err = register_path(conn, path, idev);
+
+ if (!err && ppath)
+ *ppath = path;
+
+ return err;
+}
+
+int fake_input_register(DBusConnection *conn, bdaddr_t *src,
+ bdaddr_t *dst, uint8_t ch, const char **ppath)
+{
+ struct device *idev;
+ const char *path;
+ int err;
+
+ idev = device_new(src, dst, 0, 0);
+ if (!idev)
+ return -EINVAL;
+
+ path = create_input_path(idev->major, idev->minor);
+ if (!path) {
+ device_free(idev);
+ return -EINVAL;
+ }
+
+ idev->path = g_strdup(path);
+ idev->conn = dbus_connection_ref(conn);
+
+ /* FIXME: Missing set product and vendor */
+
+ idev->fake = g_new0(struct fake_input, 1);
+ idev->fake->ch = ch;
+ idev->fake->connect = rfcomm_connect;
+ idev->fake->disconnect = fake_disconnect;
+
+ err = register_path(conn, path, idev);
+
+ if (!err && ppath)
+ *ppath = path;
+
+ return err;
+}
+
+static struct device *find_device(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ GSList *list;
+
+ for (list = devices; list != NULL; list = list->next) {
+ struct device *idev = list->data;
+
+ if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst))
+ return idev;
+ }
+
+ return NULL;
+}
+
+static struct device *find_device_by_path(const char *path)
+{
+ GSList *list;
+
+ for (list = devices; list != NULL; list = list->next) {
+ struct device *idev = list->data;
+
+ if (strcmp(idev->path, path) == 0)
+ return idev;
+ }
+
+ return NULL;
+}
+
+int input_device_unregister(DBusConnection *conn, const char *path)
+{
+ struct device *idev;
+
+ idev = find_device_by_path(path);
+ if (idev == NULL)
+ return -EINVAL;
+
+ if (idev->pending_connect) {
+ /* Pending connection running */
+ return -EBUSY;
+ }
+
+ del_stored_device_info(&idev->src, &idev->dst);
+
+ devices = g_slist_remove(devices, idev);
+
+ /*
+ * Workaround: if connected, the watch will not be able
+ * to access the D-Bus data assigned to this path
+ * because the object path data was destroyed.
+ */
+ if (idev->ctrl_watch)
+ g_source_remove(idev->ctrl_watch);
+
+ if (idev->intr_watch) {
+ g_source_remove(idev->intr_watch);
+ g_dbus_emit_signal(conn,
+ path, INPUT_DEVICE_INTERFACE,
+ "Disconnected", DBUS_TYPE_INVALID);
+ }
+
+ g_dbus_emit_signal(conn, INPUT_PATH,
+ INPUT_MANAGER_INTERFACE, "DeviceRemoved" ,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ g_dbus_unregister_interface(conn, path, INPUT_DEVICE_INTERFACE);
+
+ return 0;
+}
+
+gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct device *idev = find_device(src, dst);
+ if (!idev)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, int nsk)
+{
+ struct device *idev = find_device(src, dst);
+ if (!idev)
+ return -ENOENT;
+
+ switch (psm) {
+ case L2CAP_PSM_HIDP_CTRL:
+ idev->ctrl_sk = nsk;
+ break;
+ case L2CAP_PSM_HIDP_INTR:
+ idev->intr_sk = nsk;
+ break;
+ }
+
+ return 0;
+}
+
+int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct device *idev = find_device(src, dst);
+ if (!idev)
+ return -ENOENT;
+
+ if (idev->ctrl_sk >= 0) {
+ close(idev->ctrl_sk);
+ idev->ctrl_sk = -1;
+ }
+
+ if (idev->intr_sk >= 0) {
+ close(idev->intr_sk);
+ idev->intr_sk = -1;
+ }
+
+ return 0;
+}
+
+static gboolean fake_hid_connect(struct device *dev)
+{
+ struct fake_hid *fhid = dev->fake->priv;
+
+ return fhid->connect(dev->fake);
+}
+
+static int fake_hid_disconnect(struct device *dev)
+{
+ struct fake_hid *fhid = dev->fake->priv;
+
+ return fhid->disconnect(dev->fake);
+}
+
+int input_device_connadd(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct device *idev;
+ struct fake_hid *fake_hid;
+ struct fake_input *fake = NULL;
+ int err;
+
+ idev = find_device(src, dst);
+ if (!idev)
+ return -ENOENT;
+
+ fake_hid = get_fake_hid(idev->vendor, idev->product);
+ if (fake_hid) {
+ fake = g_try_new0(struct fake_input, 1);
+ if (!fake) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ fake->connect = fake_hid_connect;
+ fake->disconnect = fake_hid_disconnect;
+ fake->priv = fake_hid;
+ err = fake_hid_connadd(fake, idev->intr_sk, fake_hid);
+ } else
+ err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk,
+ idev->timeout, idev->name);
+ if (err < 0)
+ goto error;
+
+ idev->intr_watch = create_watch(idev->intr_sk, intr_watch_cb, idev);
+ idev->ctrl_watch = create_watch(idev->ctrl_sk, ctrl_watch_cb, idev);
+ g_dbus_emit_signal(idev->conn,
+ idev->path,
+ INPUT_DEVICE_INTERFACE,
+ "Connected",
+ DBUS_TYPE_INVALID);
+ return 0;
+
+error:
+ close(idev->ctrl_sk);
+ close(idev->intr_sk);
+ idev->ctrl_sk = -1;
+ idev->intr_sk = -1;
+ g_free(fake);
+ return err;
+}
diff --git a/utils/input/device.h b/utils/input/device.h
new file mode 100644
index 00000000..c9296ad0
--- /dev/null
+++ b/utils/input/device.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define L2CAP_PSM_HIDP_CTRL 0x11
+#define L2CAP_PSM_HIDP_INTR 0x13
+
+struct device;
+
+struct fake_input {
+ int flags;
+ GIOChannel *io;
+ int uinput; /* uinput socket */
+ int rfcomm; /* RFCOMM socket */
+ uint8_t ch; /* RFCOMM channel number */
+ gboolean (*connect) (struct device *dev);
+ int (*disconnect) (struct device *dev);
+ void *priv;
+};
+
+int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
+ struct hidp_connadd_req *hidp, const char **ppath);
+int fake_input_register(DBusConnection *conn, bdaddr_t *src,
+ bdaddr_t *dst, uint8_t ch, const char **ppath);
+int input_device_unregister(DBusConnection *conn, const char *path);
+
+gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst);
+
+int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, int nsk);
+int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);
+int input_device_connadd(bdaddr_t *src, bdaddr_t *dst);
diff --git a/utils/input/fakehid.c b/utils/input/fakehid.c
new file mode 100644
index 00000000..d752d85a
--- /dev/null
+++ b/utils/input/fakehid.c
@@ -0,0 +1,412 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/hidp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "logging.h"
+#include "device.h"
+#include "fakehid.h"
+#include "uinput.h"
+
+#ifndef KEY_REMOTE_1
+#define KEY_REMOTE_1 0x1b6
+#endif
+#ifndef KEY_REMOTE_2
+#define KEY_REMOTE_2 0x1b7
+#endif
+#ifndef KEY_REMOTE_3
+#define KEY_REMOTE_3 0x1b8
+#endif
+#ifndef KEY_REMOTE_4
+#define KEY_REMOTE_4 0x1b9
+#endif
+#ifndef KEY_REMOTE_5
+#define KEY_REMOTE_5 0x1ba
+#endif
+#ifndef KEY_REMOTE_6
+#define KEY_REMOTE_6 0x1bb
+#endif
+#ifndef KEY_REMOTE_7
+#define KEY_REMOTE_7 0x1bc
+#endif
+#ifndef KEY_REMOTE_8
+#define KEY_REMOTE_8 0x1bd
+#endif
+#ifndef KEY_REMOTE_9
+#define KEY_REMOTE_9 0x1be
+#endif
+#ifndef KEY_REMOTE_0
+#define KEY_REMOTE_0 0x1bf
+#endif
+
+#define PS3_FLAGS_MASK 0xFFFFFF00
+
+enum ps3remote_special_keys {
+ PS3R_BIT_PS = 0,
+ PS3R_BIT_ENTER = 3,
+ PS3R_BIT_L2 = 8,
+ PS3R_BIT_R2 = 9,
+ PS3R_BIT_L1 = 10,
+ PS3R_BIT_R1 = 11,
+ PS3R_BIT_TRIANGLE = 12,
+ PS3R_BIT_CIRCLE = 13,
+ PS3R_BIT_CROSS = 14,
+ PS3R_BIT_SQUARE = 15,
+ PS3R_BIT_SELECT = 16,
+ PS3R_BIT_L3 = 17,
+ PS3R_BIT_R3 = 18,
+ PS3R_BIT_START = 19,
+ PS3R_BIT_UP = 20,
+ PS3R_BIT_RIGHT = 21,
+ PS3R_BIT_DOWN = 22,
+ PS3R_BIT_LEFT = 23,
+};
+
+static unsigned int ps3remote_bits[] = {
+ [PS3R_BIT_ENTER] = 0x0b,
+ [PS3R_BIT_PS] = 0x43,
+ [PS3R_BIT_SQUARE] = 0x5f,
+ [PS3R_BIT_CROSS] = 0x5e,
+ [PS3R_BIT_CIRCLE] = 0x5d,
+ [PS3R_BIT_TRIANGLE] = 0x5c,
+ [PS3R_BIT_R1] = 0x5b,
+ [PS3R_BIT_L1] = 0x5a,
+ [PS3R_BIT_R2] = 0x59,
+ [PS3R_BIT_L2] = 0x58,
+ [PS3R_BIT_LEFT] = 0x57,
+ [PS3R_BIT_DOWN] = 0x56,
+ [PS3R_BIT_RIGHT] = 0x55,
+ [PS3R_BIT_UP] = 0x54,
+ [PS3R_BIT_START] = 0x53,
+ [PS3R_BIT_R3] = 0x52,
+ [PS3R_BIT_L3] = 0x51,
+ [PS3R_BIT_SELECT] = 0x50,
+};
+
+static unsigned int ps3remote_keymap[] = {
+ [0x16] = KEY_EJECTCD,
+ [0x64] = KEY_AUDIO,
+ [0x65] = KEY_ANGLE,
+ [0x63] = KEY_SUBTITLE,
+ [0x0f] = KEY_CLEAR,
+ [0x28] = KEY_TIME,
+ [0x00] = KEY_REMOTE_1,
+ [0x01] = KEY_REMOTE_2,
+ [0x02] = KEY_REMOTE_3,
+ [0x03] = KEY_REMOTE_4,
+ [0x04] = KEY_REMOTE_5,
+ [0x05] = KEY_REMOTE_6,
+ [0x06] = KEY_REMOTE_7,
+ [0x07] = KEY_REMOTE_8,
+ [0x08] = KEY_REMOTE_9,
+ [0x09] = KEY_REMOTE_0,
+ [0x81] = KEY_RED,
+ [0x82] = KEY_GREEN,
+ [0x80] = KEY_BLUE,
+ [0x83] = KEY_YELLOW,
+ [0x70] = KEY_INFO, /* display */
+ [0x1a] = KEY_MENU, /* top menu */
+ [0x40] = KEY_CONTEXT_MENU, /* pop up/menu */
+ [0x0e] = KEY_ESC, /* return */
+ [0x5c] = KEY_OPTION, /* options/triangle */
+ [0x5d] = KEY_BACK, /* back/circle */
+ [0x5f] = KEY_SCREEN, /* view/square */
+ [0x5e] = BTN_0, /* cross */
+ [0x54] = KEY_UP,
+ [0x56] = KEY_DOWN,
+ [0x57] = KEY_LEFT,
+ [0x55] = KEY_RIGHT,
+ [0x0b] = KEY_ENTER,
+ [0x5a] = BTN_TL, /* L1 */
+ [0x58] = BTN_TL2, /* L2 */
+ [0x51] = BTN_THUMBL, /* L3 */
+ [0x5b] = BTN_TR, /* R1 */
+ [0x59] = BTN_TR2, /* R2 */
+ [0x52] = BTN_THUMBR, /* R3 */
+ [0x43] = KEY_HOMEPAGE, /* PS button */
+ [0x50] = KEY_SELECT,
+ [0x53] = BTN_START,
+ [0x33] = KEY_REWIND, /* scan back */
+ [0x32] = KEY_PLAY,
+ [0x34] = KEY_FORWARD, /* scan forward */
+ [0x30] = KEY_PREVIOUS,
+ [0x38] = KEY_STOP,
+ [0x31] = KEY_NEXT,
+ [0x60] = KEY_FRAMEBACK, /* slow/step back */
+ [0x39] = KEY_PAUSE,
+ [0x61] = KEY_FRAMEFORWARD, /* slow/step forward */
+ [0xff] = KEY_MAX,
+};
+
+static int ps3remote_decode(char *buff, int size, unsigned int *value)
+{
+ static unsigned int lastkey = 0;
+ static unsigned int lastmask = 0;
+ int retval, mask, key, i;
+
+ if (size < 12) {
+ error("Got a shorter packet! (size %i)\n", size);
+ return KEY_RESERVED;
+ }
+
+ mask = (buff[2] << 16) + (buff[3] << 8) + buff[4];
+ key = buff[5];
+
+ /* first, check flags */
+ for (i = 0; i < 24; i++) {
+ if ((lastmask & (1 << i)) == (mask & (1 << i)))
+ continue;
+ if (ps3remote_bits[i] == 0)
+ goto error;
+ retval = ps3remote_keymap[ps3remote_bits[i]];
+ if (mask & (1 << i))
+ /* key pressed */
+ *value = 1;
+ else
+ /* key released */
+ *value = 0;
+
+ goto out;
+ }
+
+ *value = buff[11];
+ if (buff[11] == 1) {
+ retval = ps3remote_keymap[key];
+ } else
+ retval = lastkey;
+
+ if (retval == KEY_RESERVED)
+ goto error;
+ if (retval == KEY_MAX)
+ return retval;
+
+ lastkey = retval;
+
+out:
+ fflush(stdout);
+
+ lastmask = mask;
+
+ return retval;
+
+error:
+ error("ps3remote: unrecognized sequence [%#x][%#x][%#x][%#x] [%#x],"
+ "last: [%#x][%#x][%#x][%#x]",
+ buff[2], buff[3], buff[4], buff[5], buff[11],
+ lastmask >> 16, lastmask >> 8 & 0xff,
+ lastmask & 0xff, lastkey);
+ return -1;
+}
+
+static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct fake_input *fake = data;
+ struct uinput_event event;
+ unsigned int key, value = 0;
+ gsize size;
+ char buff[50];
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ error("Hangup or error on rfcomm server socket");
+ goto failed;
+ }
+
+ memset(buff, 0, sizeof(buff));
+
+ if (g_io_channel_read(chan, buff, sizeof(buff), &size) !=
+ G_IO_ERROR_NONE) {
+ error("IO Channel read error");
+ goto failed;
+ }
+
+ key = ps3remote_decode(buff, size, &value);
+ if (key == KEY_RESERVED) {
+ error("Got invalid key from decode");
+ goto failed;
+ } else if (key == KEY_MAX)
+ return TRUE;
+
+ memset(&event, 0, sizeof(event));
+ gettimeofday(&event.time, NULL);
+ event.type = EV_KEY;
+ event.code = key;
+ event.value = value;
+ if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) {
+ error("Error writing to uinput device");
+ goto failed;
+ }
+
+ memset(&event, 0, sizeof(event));
+ gettimeofday(&event.time, NULL);
+ event.type = EV_SYN;
+ event.code = SYN_REPORT;
+ if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) {
+ error("Error writing to uinput device");
+ goto failed;
+ }
+
+ return TRUE;
+
+failed:
+ ioctl(fake->uinput, UI_DEV_DESTROY);
+ close(fake->uinput);
+ fake->uinput = -1;
+ g_io_channel_unref(fake->io);
+
+ return FALSE;
+}
+
+static int ps3remote_setup_uinput(struct fake_input *fake,
+ struct fake_hid *fake_hid)
+{
+ struct uinput_dev dev;
+ int i;
+
+ fake->uinput = open("/dev/input/uinput", O_RDWR);
+ if (fake->uinput < 0) {
+ fake->uinput = open("/dev/uinput", O_RDWR);
+ if (fake->uinput < 0) {
+ fake->uinput = open("/dev/misc/uinput", O_RDWR);
+ if (fake->uinput < 0) {
+ error("Error opening uinput device file");
+ return 1;
+ }
+ }
+ }
+
+ memset(&dev, 0, sizeof(dev));
+ snprintf(dev.name, sizeof(dev.name), "%s", "PS3 Remote Controller");
+ dev.id.bustype = BUS_BLUETOOTH;
+ dev.id.vendor = fake_hid->vendor;
+ dev.id.product = fake_hid->product;
+
+ if (write(fake->uinput, &dev, sizeof(dev)) != sizeof(dev)) {
+ error("Error creating uinput device");
+ goto err;
+ }
+
+ /* enabling key events */
+ if (ioctl(fake->uinput, UI_SET_EVBIT, EV_KEY) < 0) {
+ error("Error enabling uinput device key events");
+ goto err;
+ }
+
+ /* enabling keys */
+ for (i = 0; i < 256; i++)
+ if (ps3remote_keymap[i] != KEY_RESERVED)
+ if (ioctl(fake->uinput, UI_SET_KEYBIT,
+ ps3remote_keymap[i]) < 0) {
+ error("Error enabling uinput key %i",
+ ps3remote_keymap[i]);
+ goto err;
+ }
+
+ /* creating the device */
+ if (ioctl(fake->uinput, UI_DEV_CREATE) < 0) {
+ error("Error creating uinput device");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ close(fake->uinput);
+ return 1;
+}
+
+static gboolean fake_hid_common_connect(struct fake_input *fake)
+{
+ return TRUE;
+}
+
+static int fake_hid_common_disconnect(struct fake_input *fake)
+{
+ return 0;
+}
+
+static struct fake_hid fake_hid_table[] = {
+ /* Sony PS3 remote device */
+ {
+ .vendor = 0x054c,
+ .product = 0x0306,
+ .connect = fake_hid_common_connect,
+ .disconnect = fake_hid_common_disconnect,
+ .event = ps3remote_event,
+ .setup_uinput = ps3remote_setup_uinput,
+ },
+
+ { },
+};
+
+static inline int fake_hid_match_device(uint16_t vendor, uint16_t product,
+ struct fake_hid *fhid)
+{
+ return vendor == fhid->vendor && product == fhid->product;
+}
+
+struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product)
+{
+ int i;
+
+ for (i = 0; fake_hid_table[i].vendor != 0; i++)
+ if (fake_hid_match_device(vendor, product, &fake_hid_table[i]))
+ return &fake_hid_table[i];
+
+ return NULL;
+}
+
+int fake_hid_connadd(struct fake_input *fake, int intr_sk,
+ struct fake_hid *fake_hid)
+{
+ if (fake_hid->setup_uinput(fake, fake_hid)) {
+ error("Error setting up uinput");
+ return ENOMEM;
+ }
+
+ fake->io = g_io_channel_unix_new(intr_sk);
+ g_io_channel_set_close_on_unref(fake->io, TRUE);
+ g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) fake_hid->event, fake);
+
+ return 0;
+}
diff --git a/utils/input/fakehid.h b/utils/input/fakehid.h
new file mode 100644
index 00000000..3bc2f3d6
--- /dev/null
+++ b/utils/input/fakehid.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct fake_hid;
+struct fake_input;
+
+struct fake_hid {
+ uint16_t vendor;
+ uint16_t product;
+ gboolean (*connect) (struct fake_input *fake_input);
+ int (*disconnect) (struct fake_input *fake_input);
+ gboolean (*event) (GIOChannel *chan, GIOCondition cond, gpointer data);
+ int (*setup_uinput) (struct fake_input *fake, struct fake_hid *fake_hid);
+};
+
+struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product);
+
+int fake_hid_connadd(struct fake_input *fake, int intr_sk,
+ struct fake_hid *fake_hid);
diff --git a/utils/input/input-api.txt b/utils/input/input-api.txt
new file mode 100644
index 00000000..8eb13126
--- /dev/null
+++ b/utils/input/input-api.txt
@@ -0,0 +1,103 @@
+Bluetooth input service API description
+***************************************
+
+Copyright (C) 2006-2007 Marcel Holtmann <marcel@holtmann.org>
+
+
+Input Manager hierarchy
+=======================
+
+Interface org.bluez.input.Manager
+Object path /org/bluez/input
+
+Methods array{string} ListDevices()
+
+ Returns an array of available input devices path.
+
+ string CreateDevice(string address)
+
+ Create an input device object.
+
+ On success it will return the path of the
+ newly created device object.
+
+ Possible errors: org.bluez.Error.AlreadyExists
+ org.bluez.Error.NotSupported
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.Failed
+
+ string CreateSecureDevice(string address)
+
+ Create an input device object. Pairing will
+ be initiated if needed(keyboard/combo devices).
+
+ On success it will return the path of the
+ newly created device object.
+
+ Possible errors: org.bluez.Error.AlreadyExists
+ org.bluez.Error.NotSupported
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.Failed
+
+ void RemoveDevice(string path)
+
+ Remove the input device object for a given path.
+
+ Possible errors:org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+Signals void DeviceCreated(string path)
+
+ void DeviceRemoved(string path)
+
+
+Input Device hierarchy
+======================
+
+Interface org.bluez.input.Device
+Object path /org/bluez/input/{keyboard*|mouse*|...}
+
+Methods string GetAdapter()
+
+ Returns the adapter address.
+
+ Example: "00:11:22:33:44:55"
+
+ string GetAddress()
+
+ Returns the device address.
+
+ Example: "00:11:22:33:44:55"
+
+ string GetName()
+
+ Returns the service name.
+
+ uint16 GetProductId()
+
+ Returns the product id.
+
+ uint16 GetVendorId()
+
+ Returns the vendor id.
+
+ boolean IsConnected()
+
+ Returns the connection status.
+
+ void Connect()
+
+ Connect to the input device.
+
+ Possible errors: org.bluez.Error.AlreadyConnected
+ org.bluez.Error.ConnectionAttemptFailed
+
+ void Disconnect()
+
+ Disconnect from the input device.
+
+ Possible errors: org.bluez.Error.Failed
+
+Signals void Connected()
+
+ void Disconnected()
diff --git a/utils/input/input.conf b/utils/input/input.conf
new file mode 100644
index 00000000..abfb64f2
--- /dev/null
+++ b/utils/input/input.conf
@@ -0,0 +1,9 @@
+# Configuration file for the input service
+
+# This section contains options which are not specific to any
+# particular interface
+[General]
+
+# Set idle timeout (in minutes) before the connection will
+# be disconnect (defaults to 0 for no timeout)
+#IdleTimeout=30
diff --git a/utils/input/main.c b/utils/input/main.c
new file mode 100644
index 00000000..b269c76e
--- /dev/null
+++ b/utils/input/main.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "../hcid/device.h"
+#include "logging.h"
+#include "dbus-service.h"
+#include "manager.h"
+
+#define INPUT_INTERFACE "org.bluez.Input"
+
+static DBusMessage *input_connect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *input_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *input_is_connected(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ dbus_bool_t connected = FALSE;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_BOOLEAN, &connected,
+ DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable input_methods[] = {
+ { "Connect", "", "", input_connect },
+ { "Disconnect", "", "", input_disconnect },
+ { "IsConnected", "", "b", input_is_connected },
+ { }
+};
+
+static GDBusSignalTable input_signals[] = {
+ { "Connected", "" },
+ { "Disconnected", "" },
+ { }
+};
+
+static DBusConnection *conn;
+
+static int input_probe(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ if (g_dbus_register_interface(conn, device->path, INPUT_INTERFACE,
+ input_methods, input_signals, NULL,
+ device, NULL) == FALSE)
+ return -1;
+
+ return 0;
+}
+
+static void input_remove(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ g_dbus_unregister_interface(conn, device->path, INPUT_INTERFACE);
+}
+
+static struct btd_device_driver input_driver = {
+ .name = "input",
+ .uuids = BTD_UUIDS("00001124-0000-1000-8000-00805f9b34fb"),
+ .probe = input_probe,
+ .remove = input_remove,
+};
+
+static GKeyFile *load_config_file(const char *file)
+{
+ GKeyFile *keyfile;
+ GError *err = NULL;
+
+ 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_error_free(err);
+ g_key_file_free(keyfile);
+ return NULL;
+ }
+
+ return keyfile;
+}
+
+static int input_init(void)
+{
+ GKeyFile *config;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (conn == NULL)
+ return -EIO;
+
+ config = load_config_file(CONFIGDIR "/input.conf");
+
+ if (input_manager_init(conn, config) < 0) {
+ dbus_connection_unref(conn);
+ return -EIO;
+ }
+
+ if (config)
+ g_key_file_free(config);
+
+ btd_register_device_driver(&input_driver);
+
+ return 0;
+}
+
+static void input_exit(void)
+{
+ btd_unregister_device_driver(&input_driver);
+
+ input_manager_exit();
+
+ dbus_connection_unref(conn);
+}
+
+BLUETOOTH_PLUGIN_DEFINE("input", input_init, input_exit)
diff --git a/utils/input/manager.c b/utils/input/manager.c
new file mode 100644
index 00000000..2dfb9b2d
--- /dev/null
+++ b/utils/input/manager.c
@@ -0,0 +1,801 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/hidp.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "logging.h"
+#include "textfile.h"
+
+#include "device.h"
+#include "server.h"
+#include "error.h"
+#include "manager.h"
+#include "storage.h"
+#include "glib-helper.h"
+
+struct pending_req {
+ char *adapter_path; /* Local adapter D-Bus path */
+ bdaddr_t src; /* Local adapter BT address */
+ bdaddr_t dst; /* Peer BT address */
+ DBusConnection *conn;
+ DBusMessage *msg;
+ sdp_list_t *pnp_recs;
+ sdp_list_t *hid_recs;
+ GIOChannel *ctrl_channel;
+};
+
+static int idle_timeout = 0;
+
+static GSList *device_paths = NULL; /* Input registered paths */
+
+static DBusConnection *connection = NULL;
+
+static struct pending_req *pending_req_new(DBusConnection *conn,
+ DBusMessage *msg, bdaddr_t *src, bdaddr_t *dst)
+{
+ char adapter[18], adapter_path[32];
+ struct pending_req *pr;
+ int dev_id;
+
+ pr = g_try_new0(struct pending_req, 1);
+ if (!pr)
+ return NULL;
+
+ ba2str(src, adapter);
+ dev_id = hci_devid(adapter);
+ snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id);
+
+ pr->adapter_path = g_strdup(adapter_path);
+ bacpy(&pr->src, src);
+ bacpy(&pr->dst, dst);
+ pr->conn = dbus_connection_ref(conn);
+ pr->msg = dbus_message_ref(msg);
+
+ return pr;
+}
+
+static void pending_req_free(struct pending_req *pr)
+{
+ if (!pr)
+ return;
+
+ if (pr->adapter_path)
+ g_free(pr->adapter_path);
+
+ if (pr->conn)
+ dbus_connection_unref(pr->conn);
+
+ if (pr->msg)
+ dbus_message_unref(pr->msg);
+
+ if (pr->pnp_recs)
+ sdp_list_free(pr->pnp_recs, (sdp_free_func_t) sdp_record_free);
+
+ if (pr->hid_recs)
+ sdp_list_free(pr->hid_recs, (sdp_free_func_t) sdp_record_free);
+
+ g_free(pr);
+}
+
+static void epox_endian_quirk(unsigned char *data, int size)
+{
+ /* USAGE_PAGE (Keyboard) 05 07
+ * USAGE_MINIMUM (0) 19 00
+ * USAGE_MAXIMUM (65280) 2A 00 FF <= must be FF 00
+ * LOGICAL_MINIMUM (0) 15 00
+ * LOGICAL_MAXIMUM (65280) 26 00 FF <= must be FF 00
+ */
+ unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff,
+ 0x15, 0x00, 0x26, 0x00, 0xff };
+ int i;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < size - sizeof(pattern); i++) {
+ if (!memcmp(data + i, pattern, sizeof(pattern))) {
+ data[i + 5] = 0xff;
+ data[i + 6] = 0x00;
+ data[i + 10] = 0xff;
+ data[i + 11] = 0x00;
+ }
+ }
+}
+
+static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
+{
+ sdp_data_t *pdlist, *pdlist2;
+ uint8_t attr_val;
+
+ pdlist = sdp_data_get(rec, 0x0101);
+ pdlist2 = sdp_data_get(rec, 0x0102);
+ if (pdlist) {
+ if (pdlist2) {
+ if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {
+ strncpy(req->name, pdlist2->val.str, 127);
+ strcat(req->name, " ");
+ }
+ strncat(req->name, pdlist->val.str, 127 - strlen(req->name));
+ } else
+ strncpy(req->name, pdlist->val.str, 127);
+ } else {
+ pdlist2 = sdp_data_get(rec, 0x0100);
+ if (pdlist2)
+ strncpy(req->name, pdlist2->val.str, 127);
+ }
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
+ req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
+ req->subclass = pdlist ? pdlist->val.uint8 : 0;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
+ req->country = pdlist ? pdlist->val.uint8 : 0;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
+ attr_val = pdlist ? pdlist->val.uint8 : 0;
+ if (attr_val)
+ req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
+ attr_val = pdlist ? pdlist->val.uint8 : 0;
+ if (attr_val)
+ req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
+ if (pdlist) {
+ pdlist = pdlist->val.dataseq;
+ pdlist = pdlist->val.dataseq;
+ pdlist = pdlist->next;
+
+ req->rd_data = g_try_malloc0(pdlist->unitSize);
+ if (req->rd_data) {
+ memcpy(req->rd_data, (unsigned char *) pdlist->val.str,
+ pdlist->unitSize);
+ req->rd_size = pdlist->unitSize;
+ epox_endian_quirk(req->rd_data, req->rd_size);
+ }
+ }
+}
+
+static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req)
+{
+ sdp_data_t *pdlist;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
+ req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
+ req->product = pdlist ? pdlist->val.uint16 : 0x0000;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
+ req->version = pdlist ? pdlist->val.uint16 : 0x0000;
+}
+
+static void interrupt_connect_cb(GIOChannel *chan, int err,
+ const bdaddr_t *src, const bdaddr_t *dst,
+ gpointer user_data)
+{
+ struct pending_req *pr = user_data;
+ struct hidp_connadd_req hidp;
+ const char *path;
+
+ memset(&hidp, 0, sizeof(hidp));
+
+ if (err < 0) {
+ error("connect(): %s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ g_io_channel_close(chan);
+ g_io_channel_unref(chan);
+
+ hidp.idle_to = idle_timeout * 60;
+
+ extract_hid_record(pr->hid_recs->data, &hidp);
+ if (pr->pnp_recs)
+ extract_pnp_record(pr->pnp_recs->data, &hidp);
+
+ store_device_info(&pr->src, &pr->dst, &hidp);
+
+ if (input_device_register(pr->conn, &pr->src,
+ &pr->dst, &hidp, &path) < 0) {
+ error_failed(pr->conn, pr->msg, "path registration failed");
+ goto cleanup;
+ }
+
+ g_dbus_emit_signal(pr->conn, INPUT_PATH,
+ INPUT_MANAGER_INTERFACE, "DeviceCreated",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ device_paths = g_slist_append(device_paths, g_strdup(path));
+
+ g_dbus_send_reply(pr->conn, pr->msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ goto cleanup;
+
+failed:
+ error_connection_attempt_failed(pr->conn, pr->msg, err);
+
+cleanup:
+ g_io_channel_close(pr->ctrl_channel);
+ g_io_channel_unref(pr->ctrl_channel);
+ pending_req_free(pr);
+
+ if (hidp.rd_data)
+ g_free(hidp.rd_data);
+}
+
+static void control_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct pending_req *pr = user_data;
+
+ if (err < 0) {
+ error("connect(): %s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ /* Set HID control channel */
+ pr->ctrl_channel = chan;
+
+ /* Connect to the HID interrupt channel */
+ err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, 0,
+ interrupt_connect_cb, pr);
+ if (err < 0) {
+ error("L2CAP connect failed:%s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ error_connection_attempt_failed(pr->conn, pr->msg, -err);
+ pending_req_free(pr);
+}
+
+static void create_bonding_reply(DBusPendingCall *call, void *data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ struct pending_req *pr = data;
+ DBusError derr;
+ int err;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ error("CreateBonding failed: %s(%s)",
+ derr.name, derr.message);
+ error_failed(pr->conn, pr->msg, "Authentication failed (CreateBonding)");
+ dbus_error_free(&derr);
+ dbus_message_unref(reply);
+ pending_req_free(pr);
+ return;
+ }
+
+ dbus_message_unref(reply);
+
+ err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, 0,
+ control_connect_cb, pr);
+ if (err < 0) {
+ error("L2CAP connect failed:%s (%d)", strerror(-err), -err);
+ error_connection_attempt_failed(pr->conn, pr->msg, -err);
+ pending_req_free(pr);
+ }
+}
+
+static int create_bonding(struct pending_req *pr)
+{
+ DBusPendingCall *pending;
+ DBusMessage *msg;
+ char address[18], *addr_ptr = address;
+
+ msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,
+ "org.bluez.Adapter", "CreateBonding");
+ if (!msg) {
+ error("Unable to allocate new method call");
+ return -1;
+ }
+
+ ba2str(&pr->dst, address);
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, DBUS_TYPE_INVALID);
+ if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {
+ error("Can't send D-Bus message.");
+ dbus_message_unref(msg);
+ return -1;
+ }
+ dbus_pending_call_set_notify(pending, create_bonding_reply, pr, NULL);
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(msg);
+ return 0;
+}
+
+static void hid_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct pending_req *pr = user_data;
+
+ if (err < 0) {
+ error_not_supported(pr->conn, pr->msg);
+ error("SDP search error: %s (%d)", strerror(-err), -err);
+ goto fail;
+ }
+
+ if (!recs || !recs->data) {
+ error_not_supported(pr->conn, pr->msg);
+ error("Invalid HID service record length");
+ goto fail;
+ }
+
+ pr->hid_recs = recs;
+
+ if (strcmp("CreateSecureDevice", dbus_message_get_member(pr->msg)) == 0) {
+ sdp_data_t *d;
+
+ /* Pairing mandatory for keyboard and combo */
+ d = sdp_data_get(pr->hid_recs->data,
+ SDP_ATTR_HID_DEVICE_SUBCLASS);
+ if (d && (d->val.uint8 & 0x40) &&
+ !has_bonding(&pr->src, &pr->dst)) {
+ if (create_bonding(pr) < 0) {
+ error_failed(pr->conn, pr->msg,
+ "Unable to initialize bonding process");
+ goto fail;
+ }
+ /* Wait bonding reply */
+ return;
+ }
+
+ /* Otherwise proceede L2CAP connection */
+ }
+
+ /* No encryption or link key already exists -- connect control channel */
+ err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, 0,
+ control_connect_cb, pr);
+ if (err < 0) {
+ error("L2CAP connect failed:%s (%d)", strerror(-err), -err);
+ error_connection_attempt_failed(pr->conn, pr->msg, -err);
+ goto fail;
+ }
+
+ /* Wait L2CAP connect */
+ return;
+
+fail:
+ pending_req_free(pr);
+}
+
+static void pnp_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct pending_req *pr = user_data;
+ uuid_t uuid;
+
+ if (err < 0) {
+ error_not_supported(pr->conn, pr->msg);
+ error("SDP search error: %s (%d)", strerror(-err), -err);
+ goto fail;
+ }
+
+ if (!recs || !recs->data) {
+ error_not_supported(pr->conn, pr->msg);
+ error("Invalid PnP service record length");
+ goto fail;
+ }
+
+ pr->pnp_recs = recs;
+ sdp_uuid16_create(&uuid, HID_SVCLASS_ID);
+ err = bt_search_service(&pr->src, &pr->dst, &uuid, hid_record_cb,
+ pr, NULL);
+ if (err < 0) {
+ error_not_supported(pr->conn, pr->msg);
+ error("HID service search request failed");
+ goto fail;
+ }
+
+ return;
+
+fail:
+ pending_req_free(pr);
+}
+
+static void headset_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct pending_req *pr = user_data;
+ sdp_record_t *rec;
+ sdp_list_t *protos;
+ const char *path;
+ uint8_t ch;
+
+ if (err < 0) {
+ error_not_supported(pr->conn, pr->msg);
+ error("SDP search error: %s (%d)", strerror(-err), -err);
+ goto fail;
+ }
+
+ if (!recs || !recs->data) {
+ error_not_supported(pr->conn, pr->msg);
+ error("Invalid headset service record length");
+ goto fail;
+ }
+
+ rec = recs->data;
+
+ if (sdp_get_access_protos(rec, &protos) < 0) {
+ error_not_supported(pr->conn, pr->msg);
+ goto fail;
+ }
+
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+ sdp_record_free(rec);
+
+ if (ch <= 0) {
+ error_not_supported(pr->conn, pr->msg);
+ error("Invalid RFCOMM channel");
+ goto fail;
+ }
+
+ /* FIXME: Store the fake input data */
+
+ if (fake_input_register(pr->conn, &pr->src, &pr->dst, ch, &path) < 0) {
+ error("D-Bus path registration failed:%s", path);
+ error_failed(pr->conn, pr->msg, "Path registration failed");
+ goto fail;
+ }
+
+ g_dbus_emit_signal(pr->conn, INPUT_PATH,
+ INPUT_MANAGER_INTERFACE, "DeviceCreated",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ device_paths = g_slist_append(device_paths, g_strdup(path));
+
+ g_dbus_send_reply(pr->conn, pr->msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+fail:
+ pending_req_free(pr);
+}
+
+static inline DBusMessage *adapter_not_available(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Adapter not available");
+}
+
+static inline DBusMessage *already_exists(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists",
+ "Input Already exists");
+}
+
+static inline DBusMessage *not_supported(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotSupported",
+ "Not supported");
+}
+
+static inline DBusMessage *does_not_exist(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists",
+ "Input doesn't exist");
+}
+
+static DBusMessage *create_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct pending_req *pr;
+ const char *addr;
+ bdaddr_t src, dst;
+ uint32_t cls = 0;
+ int dev_id, err;
+ uuid_t uuid;
+ bt_callback_t cb;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ /* Get the default adapter */
+ dev_id = hci_get_route(NULL);
+ if (dev_id < 0) {
+ error("Bluetooth adapter not available");
+ return adapter_not_available(msg);
+ }
+
+ if (hci_devba(dev_id, &src) < 0) {
+ error("Can't get local adapter device info");
+ return adapter_not_available(msg);
+ }
+
+ str2ba(addr, &dst);
+ if (input_device_is_registered(&src, &dst))
+ return already_exists(msg);
+
+ if (read_device_class(&src, &dst, &cls) < 0) {
+ error("Device class not available");
+ return not_supported(msg);
+ }
+
+ pr = pending_req_new(conn, msg, &src, &dst);
+ if (!pr)
+ return NULL;
+
+ switch (cls & 0x1f00) {
+ case 0x0500: /* Peripheral */
+ case 0x0200: /* Phone */
+ sdp_uuid16_create(&uuid, PNP_INFO_SVCLASS_ID);
+ cb = pnp_record_cb;
+ break;
+ case 0x0400: /* Fake input */
+ sdp_uuid16_create(&uuid, HEADSET_SVCLASS_ID);
+ cb = headset_record_cb;
+ break;
+ default:
+ pending_req_free(pr);
+ return not_supported(msg);
+ }
+
+ err = bt_search_service(&src, &dst, &uuid, cb, pr, NULL);
+ if (err < 0) {
+ pending_req_free(pr);
+ return not_supported(msg);
+ }
+
+ return NULL;
+}
+
+static DBusMessage *remove_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ GSList *l;
+ const char *path;
+ int err;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ l = g_slist_find_custom(device_paths, path, (GCompareFunc) strcmp);
+ if (!l)
+ return does_not_exist(msg);
+
+ err = input_device_unregister(conn, path);
+ if (err < 0)
+ return create_errno_message(msg, -err);
+
+ g_free(l->data);
+ device_paths = g_slist_remove(device_paths, l->data);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *list_devices(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, iter_array;
+ DBusMessage *reply;
+ GSList *paths;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &iter_array);
+
+ for (paths = device_paths; paths != NULL; paths = paths->next) {
+ const char *ppath = paths->data;
+ dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_STRING, &ppath);
+ }
+
+ dbus_message_iter_close_container(&iter, &iter_array);
+
+ return reply;
+}
+
+static void manager_unregister(void *data)
+{
+ info("Unregistered manager path");
+
+ g_slist_foreach(device_paths, (GFunc) free, NULL);
+
+ g_slist_free(device_paths);
+}
+
+/*
+ * Stored inputs registration functions
+ */
+
+static void stored_input(char *key, char *value, void *data)
+{
+ const char *path;
+ struct hidp_connadd_req hidp;
+ bdaddr_t dst, *src = data;
+
+ str2ba(key, &dst);
+
+ memset(&hidp, 0, sizeof(hidp));
+
+ if (parse_stored_device_info(value, &hidp) < 0)
+ return;
+
+ /*
+ * Repeated entries for the same remote device are
+ * acceptable since the source is different.
+ */
+ if (input_device_register(connection, src, &dst, &hidp, &path) < 0)
+ goto cleanup;
+
+ device_paths = g_slist_append(device_paths, g_strdup(path));
+cleanup:
+ if (hidp.rd_data)
+ g_free(hidp.rd_data);
+}
+
+/* hidd to input transition function */
+static void stored_hidd(char *key, char *value, void *data)
+{
+ struct hidp_connadd_req hidp;
+ char *str, filename[PATH_MAX + 1], addr[18];
+ bdaddr_t dst, *src = data;
+
+ ba2str(src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "input");
+
+ str = textfile_get(filename, key);
+ if (str) {
+ /* Skip: entry found in input file */
+ free(str);
+ return;
+ }
+
+ memset(&hidp, 0, sizeof(hidp));
+
+ if (parse_stored_hidd(value, &hidp) < 0)
+ return;
+
+ str2ba(key, &dst);
+ store_device_info(src, &dst, &hidp);
+ if (hidp.rd_data)
+ g_free(hidp.rd_data);
+}
+
+static void register_stored_inputs(void)
+{
+ char dirname[PATH_MAX + 1];
+ char filename[PATH_MAX + 1];
+ struct dirent *de;
+ DIR *dir;
+ bdaddr_t src;
+
+ snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
+
+ dir = opendir(dirname);
+ if (!dir)
+ return;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (!isdigit(de->d_name[0]))
+ continue;
+
+ str2ba(de->d_name, &src);
+
+ /* move the hidd entries to the input storage */
+ create_name(filename, PATH_MAX, STORAGEDIR,
+ de->d_name, "hidd");
+ textfile_foreach(filename, stored_hidd, &src);
+
+ /* load the input stored devices */
+ create_name(filename, PATH_MAX, STORAGEDIR,
+ de->d_name, "input");
+
+ textfile_foreach(filename, stored_input, &src);
+ }
+
+ closedir(dir);
+}
+
+static GDBusMethodTable manager_methods[] = {
+ { "ListDevices", "", "as", list_devices },
+ { "CreateDevice", "s", "s", create_device,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "CreateSecureDevice", "s", "s", create_device,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "RemoveDevice", "s", "", remove_device },
+ { }
+};
+
+static GDBusSignalTable manager_signals[] = {
+ { "DeviceCreated", "s" },
+ { "DeviceRemoved", "s" },
+ { }
+};
+
+int input_manager_init(DBusConnection *conn, GKeyFile *config)
+{
+ GError *err = NULL;
+
+ if (config) {
+ idle_timeout = g_key_file_get_integer(config, "General",
+ "IdleTimeout", &err);
+ if (err) {
+ debug("input.conf: %s", err->message);
+ g_error_free(err);
+ }
+ }
+
+ if (g_dbus_register_interface(conn, INPUT_PATH, INPUT_MANAGER_INTERFACE,
+ manager_methods, manager_signals, NULL,
+ NULL, manager_unregister) == FALSE) {
+ error("Failed to register %s interface to %s",
+ INPUT_MANAGER_INTERFACE, INPUT_PATH);
+ return -1;
+ }
+
+ connection = dbus_connection_ref(conn);
+
+ info("Registered input manager path:%s", INPUT_PATH);
+
+ /* Register well known HID devices */
+ register_stored_inputs();
+
+ server_start();
+
+ return 0;
+}
+
+void input_manager_exit(void)
+{
+ g_dbus_unregister_interface(connection, INPUT_PATH,
+ INPUT_MANAGER_INTERFACE);
+
+ server_stop();
+
+ dbus_connection_unref(connection);
+
+ connection = NULL;
+}
diff --git a/utils/input/manager.h b/utils/input/manager.h
new file mode 100644
index 00000000..8f9d999e
--- /dev/null
+++ b/utils/input/manager.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define INPUT_PATH "/org/bluez/input"
+#define INPUT_MANAGER_INTERFACE "org.bluez.input.Manager"
+
+int input_manager_init(DBusConnection *conn, GKeyFile *config);
+void input_manager_exit(void);
diff --git a/utils/input/server.c b/utils/input/server.c
new file mode 100644
index 00000000..9267e4aa
--- /dev/null
+++ b/utils/input/server.c
@@ -0,0 +1,153 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/hidp.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "logging.h"
+
+#include "device.h"
+#include "server.h"
+#include "storage.h"
+#include "dbus-service.h"
+#include "glib-helper.h"
+
+static const char *HID_UUID = "00001124-0000-1000-8000-00805f9b34fb";
+
+struct authorization_data {
+ bdaddr_t src;
+ bdaddr_t dst;
+};
+
+static void auth_callback(DBusError *derr, void *user_data)
+{
+ struct authorization_data *auth = user_data;
+
+ if (derr) {
+ error("Access denied: %s", derr->message);
+ if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY))
+ service_cancel_auth(&auth->src, &auth->dst);
+
+ input_device_close_channels(&auth->src, &auth->dst);
+ } else
+ input_device_connadd(&auth->src, &auth->dst);
+
+ g_free(auth);
+}
+
+static int authorize_device(const bdaddr_t *src, const bdaddr_t *dst)
+{
+ struct authorization_data *auth;
+
+ auth = g_new0(struct authorization_data, 1);
+ bacpy(&auth->src, src);
+ bacpy(&auth->dst, dst);
+
+ return service_req_auth(src, dst, HID_UUID,
+ auth_callback, auth);
+}
+
+static void connect_event_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer data)
+{
+ int sk, psm = GPOINTER_TO_UINT(data);
+
+ if (err < 0) {
+ error("accept: %s (%d)", strerror(-err), -err);
+ return;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ debug("Incoming connection on PSM %d", psm);
+
+ if (input_device_set_channel(src, dst, psm, sk) < 0) {
+ /* Send unplug virtual cable to unknown devices */
+ if (psm == L2CAP_PSM_HIDP_CTRL) {
+ unsigned char unplug[] = { 0x15 };
+ int err;
+ err = write(sk, unplug, sizeof(unplug));
+ }
+ close(sk);
+ return;
+ }
+
+ if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(src, dst) < 0))
+ input_device_close_channels(src, dst);
+
+ return;
+}
+
+static GIOChannel *ctrl_io = NULL;
+static GIOChannel *intr_io = NULL;
+
+int server_start(void)
+{
+ ctrl_io = bt_l2cap_listen(BDADDR_ANY, L2CAP_PSM_HIDP_CTRL, 0, 0,
+ connect_event_cb,
+ GUINT_TO_POINTER(L2CAP_PSM_HIDP_CTRL));
+ if (!ctrl_io) {
+ error("Failed to listen on control channel");
+ return -1;
+ }
+ g_io_channel_set_close_on_unref(ctrl_io, TRUE);
+
+ intr_io = bt_l2cap_listen(BDADDR_ANY, L2CAP_PSM_HIDP_INTR, 0, 0,
+ connect_event_cb,
+ GUINT_TO_POINTER(L2CAP_PSM_HIDP_INTR));
+ if (!intr_io) {
+ error("Failed to listen on interrupt channel");
+ g_io_channel_unref(ctrl_io);
+ ctrl_io = NULL;
+ }
+ g_io_channel_set_close_on_unref(intr_io, TRUE);
+
+ return 0;
+}
+
+void server_stop(void)
+{
+ if (intr_io)
+ g_io_channel_unref(intr_io);
+
+ if (ctrl_io)
+ g_io_channel_unref(ctrl_io);
+}
diff --git a/utils/input/server.h b/utils/input/server.h
new file mode 100644
index 00000000..75cf704c
--- /dev/null
+++ b/utils/input/server.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 server_start(void);
+void server_stop(void);
diff --git a/utils/input/storage.c b/utils/input/storage.c
new file mode 100644
index 00000000..25894a5b
--- /dev/null
+++ b/utils/input/storage.c
@@ -0,0 +1,364 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hidp.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "textfile.h"
+
+#include "storage.h"
+
+static inline int create_filename(char *buf, size_t size,
+ bdaddr_t *bdaddr, const char *name)
+{
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+
+ return create_name(buf, size, STORAGEDIR, addr, name);
+}
+
+int parse_stored_hidd(const char *str, struct hidp_connadd_req *req)
+{
+ char tmp[3];
+ char *desc;
+ unsigned int vendor, product, version, subclass, country, parser, pos;
+ int i;
+
+ desc = malloc(4096);
+ if (!desc)
+ return -ENOMEM;
+
+ memset(desc, 0, 4096);
+
+ sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n",
+ &vendor, &product, &version, &subclass, &country,
+ &parser, desc, &req->flags, &pos);
+
+ req->vendor = vendor;
+ req->product = product;
+ req->version = version;
+ req->subclass = subclass;
+ req->country = country;
+ req->parser = parser;
+
+ req->rd_size = strlen(desc) / 2;
+ req->rd_data = g_try_malloc0(req->rd_size);
+ if (!req->rd_data) {
+ g_free(desc);
+ return -ENOMEM;
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < req->rd_size; i++) {
+ memcpy(tmp, desc + (i * 2), 2);
+ req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ g_free(desc);
+
+ return 0;
+}
+
+int parse_stored_device_info(const char *str, struct hidp_connadd_req *req)
+{
+ char tmp[3];
+ const char *desc;
+ unsigned int vendor, product, version, subclass, country, parser, pos;
+ size_t len;
+ int i;
+
+ sscanf(str, "%04X:%04X:%04X %02X %02X %04X %08X %n",
+ &vendor, &product, &version, &subclass, &country,
+ &parser, &req->flags, &pos);
+
+ desc = &str[pos];
+ len = strlen(desc);
+ if (len <= 0)
+ return -ENOENT;
+
+ req->vendor = vendor;
+ req->product = product;
+ req->version = version;
+ req->subclass = subclass;
+ req->country = country;
+ req->parser = parser;
+
+ req->rd_size = len / 2;
+ req->rd_data = g_try_malloc0(req->rd_size);
+ if (!req->rd_data) {
+ return -ENOMEM;
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < req->rd_size; i++) {
+ memcpy(tmp, desc + (i * 2), 2);
+ req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ return 0;
+}
+
+int get_stored_device_info(bdaddr_t *src, bdaddr_t *dst,
+ struct hidp_connadd_req *req)
+{
+ char filename[PATH_MAX + 1], *str;
+ char peer[18];
+ int err;
+
+ create_filename(filename, PATH_MAX, src, "input");
+
+ ba2str(dst, peer);
+ str = textfile_get(filename, peer);
+ if (!str)
+ return -ENOENT;
+
+ err = parse_stored_device_info(str, req);
+
+ free(str);
+
+ return err;
+}
+
+int del_stored_device_info(bdaddr_t *src, bdaddr_t *dst)
+{
+ char filename[PATH_MAX + 1];
+ char addr[18];
+
+ ba2str(dst, addr);
+
+ create_filename(filename, PATH_MAX, src, "hidd");
+ textfile_del(filename, addr);
+
+ create_filename(filename, PATH_MAX, src, "input");
+ return textfile_del(filename, addr);
+}
+
+int store_device_info(bdaddr_t *src, bdaddr_t *dst, struct hidp_connadd_req *req)
+{
+ char filename[PATH_MAX + 1], *str, *desc;
+ int i, err, size;
+ char addr[18];
+
+ create_filename(filename, PATH_MAX, src, "input");
+
+ size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 2 + 9;
+ str = g_try_malloc0(size);
+ if (!str)
+ return -ENOMEM;
+
+ desc = g_try_malloc0((req->rd_size * 2) + 1);
+ if (!desc) {
+ g_free(str);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < req->rd_size; i++)
+ sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]);
+
+ snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %08X %s",
+ req->vendor, req->product, req->version,
+ req->subclass, req->country, req->parser,
+ req->flags, desc);
+
+ g_free(desc);
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(dst, addr);
+
+ err = textfile_put(filename, addr, str);
+
+ g_free(str);
+
+ return err;
+}
+
+int read_device_name(bdaddr_t *src, bdaddr_t *dst, char **name)
+{
+ char filename[PATH_MAX + 1], addr[18], *str;
+ int len;
+
+ create_filename(filename, PATH_MAX, src, "names");
+
+ ba2str(dst, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ len = strlen(str);
+
+ /* HID max name size is 128 chars */
+ if (len < 128) {
+ *name = str;
+ return 0;
+ }
+
+ *name = g_try_malloc0(128);
+ if (!*name)
+ return -ENOMEM;
+
+ snprintf(*name, 128, "%s", str);
+
+ free(str);
+
+ return 0;
+}
+
+int read_device_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls)
+{
+ char filename[PATH_MAX + 1], *str;
+ char addr[18];
+
+ ba2str(src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "classes");
+
+ ba2str(dst, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ if (sscanf(str, "%x", cls) != 1) {
+ g_free(str);
+ return -ENOENT;
+ }
+
+ g_free(str);
+
+ return 0;
+}
+
+int encrypt_link(bdaddr_t *src, bdaddr_t *dst)
+{
+ char filename[PATH_MAX + 1];
+ struct hci_conn_info_req *cr;
+ int dd, err, dev_id;
+ char addr[18], *str;
+
+ create_filename(filename, PATH_MAX, src, "linkkeys");
+
+ ba2str(dst, addr);
+
+ str = textfile_get(filename, addr);
+ if (!str) {
+ error("Encryption link key not found");
+ return -ENOKEY;
+ }
+
+ free(str);
+
+ cr = g_try_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr)
+ return -ENOMEM;
+
+ ba2str(src, addr);
+
+ dev_id = hci_devid(addr);
+ if (dev_id < 0) {
+ g_free(cr);
+ return -errno;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ g_free(cr);
+ return -errno;
+ }
+
+ bacpy(&cr->bdaddr, dst);
+ cr->type = ACL_LINK;
+
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0)
+ goto fail;
+
+ if (cr->conn_info->link_mode & HCI_LM_ENCRYPT) {
+ /* Already encrypted */
+ goto done;
+ }
+
+ if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 1000) < 0) {
+ error("Link authentication failed: %s (%d)",
+ strerror(errno), errno);
+ goto fail;
+ }
+
+ if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), 1, 1000) < 0) {
+ error("Link encryption failed: %s (%d)",
+ strerror(errno), errno);
+ goto fail;
+ }
+
+done:
+ g_free(cr);
+
+ hci_close_dev(dd);
+
+ return 0;
+
+fail:
+ g_free(cr);
+
+ err = errno;
+ hci_close_dev(dd);
+
+ return -err;
+}
+
+gboolean has_bonding(bdaddr_t *src, bdaddr_t *dst)
+{
+ char filename[PATH_MAX + 1];
+ char addr[18], *str;
+
+ create_filename(filename, PATH_MAX, src, "linkkeys");
+
+ ba2str(dst, addr);
+
+ str = textfile_get(filename, addr);
+ if (!str)
+ return FALSE;
+
+ free(str);
+
+ return TRUE;
+}
diff --git a/utils/input/storage.h b/utils/input/storage.h
new file mode 100644
index 00000000..90ba4a87
--- /dev/null
+++ b/utils/input/storage.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 get_stored_device_info(bdaddr_t *src, bdaddr_t *dst,
+ struct hidp_connadd_req *req);
+
+int del_stored_device_info(bdaddr_t *src, bdaddr_t *dst);
+
+int store_device_info(bdaddr_t *src, bdaddr_t *dst,
+ struct hidp_connadd_req *req);
+
+int parse_stored_hidd(const char *str, struct hidp_connadd_req *req);
+int parse_stored_device_info(const char *str,
+ struct hidp_connadd_req *req);
+
+int read_device_name(bdaddr_t *src, bdaddr_t *dst, char **name);
+int read_device_class(bdaddr_t *src, bdaddr_t *dst, uint32_t *cls);
+
+int encrypt_link(bdaddr_t *src, bdaddr_t *dst);
+
+gboolean has_bonding(bdaddr_t *src, bdaddr_t *dst);
diff --git a/utils/input/test-input b/utils/input/test-input
new file mode 100755
index 00000000..7f41b6f6
--- /dev/null
+++ b/utils/input/test-input
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Manager')
+
+conn = manager.ActivateService('input')
+
+input = dbus.Interface(bus.get_object(conn, '/org/bluez/input'),
+ 'org.bluez.input.Manager')
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <command>" % (sys.argv[0])
+ print ""
+ print " list"
+ print " create <address>"
+ print " remove <path>"
+ sys.exit(1)
+
+if (sys.argv[1] == "list"):
+ list = input.ListDevices()
+ print list
+ sys.exit(0)
+
+if (sys.argv[1] == "create"):
+ if (len(sys.argv) < 3):
+ print "Need address parameter"
+ else:
+ device = input.CreateSecureDevice(sys.argv[2])
+ print device
+ sys.exit(0)
+
+if (sys.argv[1] == "remove"):
+ if (len(sys.argv) < 3):
+ print "Need object path parameter"
+ else:
+ input.RemoveDevice(sys.argv[2])
+ sys.exit(0)
+
+print "Unknown command"
+sys.exit(1)
diff --git a/utils/install-sh b/utils/install-sh
new file mode 100755
index 00000000..a5897de6
--- /dev/null
+++ b/utils/install-sh
@@ -0,0 +1,519 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2006-12-25.00
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dst_arg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ -*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/utils/ltmain.sh b/utils/ltmain.sh
new file mode 100644
index 00000000..8e5a9304
--- /dev/null
+++ b/utils/ltmain.sh
@@ -0,0 +1,6930 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007 Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+basename="s,^.*/,,g"
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# The name of this program:
+progname=`echo "$progpath" | $SED $basename`
+modename="$progname"
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.5.24
+TIMESTAMP=" (1.1220.2.456 2007/06/24 02:25:32)"
+
+# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE).
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell, and then maybe $echo will work.
+ exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit $EXIT_SUCCESS
+fi
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ SP2NL='tr \040 \012'
+ NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ SP2NL='tr \100 \n'
+ NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test \"\${$lt_var+set}\" = set; then
+ save_$lt_var=\$$lt_var
+ $lt_var=C
+ export $lt_var
+ fi"
+done
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" $lt_nl"
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ $echo "$modename: not configured to build any kind of library" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit $EXIT_FAILURE
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+duplicate_deps=no
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $mkdir "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || {
+ $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2
+ exit $EXIT_FAILURE
+ }
+ fi
+
+ $echo "X$my_tmpdir" | $Xsed
+}
+
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid ()
+{
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+ $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+ win32_nmres=`eval $NM -f posix -A $1 | \
+ $SED -n -e '1,100{
+ / I /{
+ s,.*,import,
+ p
+ q
+ }
+ }'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $echo $win32_libid_type
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ CC_quoted="$CC_quoted $arg"
+ done
+ case "$@ " in
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit $EXIT_FAILURE
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+
+ $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)"
+ $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $?
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2
+ exit $EXIT_FAILURE
+ fi
+}
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+ my_status=""
+
+ $show "${rm}r $my_gentop"
+ $run ${rm}r "$my_gentop"
+ $show "$mkdir $my_gentop"
+ $run $mkdir "$my_gentop"
+ my_status=$?
+ if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then
+ exit $my_status
+ fi
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'`
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ extracted_serial=`expr $extracted_serial + 1`
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir="$my_gentop/$my_xlib_u"
+
+ $show "${rm}r $my_xdir"
+ $run ${rm}r "$my_xdir"
+ $show "$mkdir $my_xdir"
+ $run $mkdir "$my_xdir"
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then
+ exit $exit_status
+ fi
+ case $host in
+ *-darwin*)
+ $show "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ if test -z "$run"; then
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'`
+ darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ $show "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we have a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+ lipo -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ ${rm}r unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd "$darwin_orig_dir"
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ fi # $run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ func_extract_archives_result="$my_oldobjs"
+}
+# End of Shell function definitions
+#####################################
+
+# Darwin sucks
+eval std_shrext=\"$shrext_cmds\"
+
+disable_libs=no
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+ arg="$1"
+ shift
+
+ case $arg in
+ -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ execute_dlfiles)
+ execute_dlfiles="$execute_dlfiles $arg"
+ ;;
+ tag)
+ tagname="$arg"
+ preserve_args="${preserve_args}=$arg"
+
+ # Check whether tagname contains only valid characters
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ $echo "$progname: invalid tag name: $tagname" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $tagname in
+ CC)
+ # Don't test for the "default" C tag, as we know, it's there, but
+ # not specially marked.
+ ;;
+ *)
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
+ taglist="$taglist $tagname"
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
+ else
+ $echo "$progname: ignoring unknown tag $tagname" 1>&2
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ eval "$prev=\$arg"
+ ;;
+ esac
+
+ prev=
+ prevopt=
+ continue
+ fi
+
+ # Have we seen a non-optional argument yet?
+ case $arg in
+ --help)
+ show_help=yes
+ ;;
+
+ --version)
+ echo "\
+$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP
+
+Copyright (C) 2007 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+ exit $?
+ ;;
+
+ --config)
+ ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
+ done
+ exit $?
+ ;;
+
+ --debug)
+ $echo "$progname: enabling shell trace mode"
+ set -x
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --dry-run | -n)
+ run=:
+ ;;
+
+ --features)
+ $echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ $echo "enable shared libraries"
+ else
+ $echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ $echo "enable static libraries"
+ else
+ $echo "disable static libraries"
+ fi
+ exit $?
+ ;;
+
+ --finish) mode="finish" ;;
+
+ --mode) prevopt="--mode" prev=mode ;;
+ --mode=*) mode="$optarg" ;;
+
+ --preserve-dup-deps) duplicate_deps="yes" ;;
+
+ --quiet | --silent)
+ show=:
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --tag)
+ prevopt="--tag"
+ prev=tag
+ preserve_args="$preserve_args --tag"
+ ;;
+ --tag=*)
+ set tag "$optarg" ${1+"$@"}
+ shift
+ prev=tag
+ preserve_args="$preserve_args --tag"
+ ;;
+
+ -dlopen)
+ prevopt="-dlopen"
+ prev=execute_dlfiles
+ ;;
+
+ -*)
+ $echo "$modename: unrecognized option \`$arg'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+
+ *)
+ nonopt="$arg"
+ break
+ ;;
+ esac
+done
+
+if test -n "$prevopt"; then
+ $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+fi
+
+case $disable_libs in
+no)
+ ;;
+shared)
+ build_libtool_libs=no
+ build_old_libs=yes
+ ;;
+static)
+ build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+ ;;
+esac
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+ # Infer the operation mode.
+ if test -z "$mode"; then
+ $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+ $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2
+ case $nonopt in
+ *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+ mode=link
+ for arg
+ do
+ case $arg in
+ -c)
+ mode=compile
+ break
+ ;;
+ esac
+ done
+ ;;
+ *db | *dbx | *strace | *truss)
+ mode=execute
+ ;;
+ *install*|cp|mv)
+ mode=install
+ ;;
+ *rm)
+ mode=uninstall
+ ;;
+ *)
+ # If we have no mode, but dlfiles were specified, then do execute mode.
+ test -n "$execute_dlfiles" && mode=execute
+
+ # Just use the default operation mode.
+ if test -z "$mode"; then
+ if test -n "$nonopt"; then
+ $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+ else
+ $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+ fi
+ fi
+ ;;
+ esac
+ fi
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$modename --help --mode=$mode' for more information."
+
+ # These modes are in order of execution frequency so that they run quickly.
+ case $mode in
+ # libtool compile mode
+ compile)
+ modename="$modename: compile"
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ if test -n "$libobj" ; then
+ $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ arg_mode=target
+ continue
+ ;;
+
+ -static | -prefer-pic | -prefer-non-pic)
+ later="$later $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ lastarg="$lastarg $arg"
+ done
+ IFS="$save_ifs"
+ lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ * )
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+ case $lastarg in
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, and some SunOS ksh mistreat backslash-escaping
+ # in scan sets (worked around with variable expansion),
+ # and furthermore cannot handle '|' '&' '(' ')' in scan sets
+ # at all, so we specify them separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ lastarg="\"$lastarg\""
+ ;;
+ esac
+
+ base_compile="$base_compile $lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ $echo "$modename: you must specify an argument for -Xcompile"
+ exit $EXIT_FAILURE
+ ;;
+ target)
+ $echo "$modename: you must specify a target with \`-o'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ *)
+ # Get the name of the library object.
+ [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ xform='[cCFSifmso]'
+ case $libobj in
+ *.ada) xform=ada ;;
+ *.adb) xform=adb ;;
+ *.ads) xform=ads ;;
+ *.asm) xform=asm ;;
+ *.c++) xform=c++ ;;
+ *.cc) xform=cc ;;
+ *.ii) xform=ii ;;
+ *.class) xform=class ;;
+ *.cpp) xform=cpp ;;
+ *.cxx) xform=cxx ;;
+ *.[fF][09]?) xform=[fF][09]. ;;
+ *.for) xform=for ;;
+ *.java) xform=java ;;
+ *.obj) xform=obj ;;
+ esac
+
+ libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+ case $libobj in
+ *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+ *)
+ $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -static)
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"`
+ case $qlibobj in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qlibobj="\"$qlibobj\"" ;;
+ esac
+ test "X$libobj" != "X$qlibobj" \
+ && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && $echo "$modename: libobj name \`$libobj' may not contain shell special characters."
+ objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$obj"; then
+ xdir=
+ else
+ xdir=$xdir/
+ fi
+ lobj=${xdir}$objdir/$objname
+
+ if test -z "$base_compile"; then
+ $echo "$modename: you must specify a compilation command" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ $run $rm $removelist
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ removelist="$removelist $output_obj $lockfile"
+ trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $run ln "$progpath" "$lockfile" 2>/dev/null; do
+ $show "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+ $echo "$srcfile" > "$lockfile"
+ fi
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+ qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"`
+ case $qsrcfile in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qsrcfile="\"$qsrcfile\"" ;;
+ esac
+
+ $run $rm "$libobj" "${libobj}T"
+
+ # Create a libtool object file (analogous to a ".la" file),
+ # but don't create it if we're doing a dry run.
+ test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ if test ! -d "${xdir}$objdir"; then
+ $show "$mkdir ${xdir}$objdir"
+ $run $mkdir ${xdir}$objdir
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "${xdir}$objdir"; then
+ exit $exit_status
+ fi
+ fi
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ $run $rm "$lobj" "$output_obj"
+
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ test -n "$output_obj" && $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ $show "$mv $output_obj $lobj"
+ if $run $mv $output_obj $lobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the PIC object to the libtool object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ else
+ # No PIC object so indicate it doesn't exist in the libtool
+ # object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ $run $rm "$obj" "$output_obj"
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ $show "$mv $output_obj $obj"
+ if $run $mv $output_obj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+ else
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+ fi
+
+ $run $mv "${libobj}T" "${libobj}"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ $run $rm "$lockfile"
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool link mode
+ link | relink)
+ modename="$modename: link"
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args="$nonopt"
+ base_compile="$nonopt $@"
+ compile_command="$nonopt"
+ finalize_command="$nonopt"
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+
+ avoid_version=no
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ notinst_path= # paths that contain not-installed libtool libraries
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+ ;;
+ *) qarg=$arg ;;
+ esac
+ libtool_args="$libtool_args $qarg"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ compile_command="$compile_command @OUTPUT@"
+ finalize_command="$finalize_command @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ compile_command="$compile_command @SYMFILE@"
+ finalize_command="$finalize_command @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ if test ! -f "$arg"; then
+ $echo "$modename: symbol file \`$arg' does not exist"
+ exit $EXIT_FAILURE
+ fi
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat $save_arg`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit $EXIT_FAILURE
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ done
+ else
+ $echo "$modename: link input file \`$save_arg' does not exist"
+ exit $EXIT_FAILURE
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ compile_command="$compile_command $wl$qarg"
+ finalize_command="$finalize_command $wl$qarg"
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ darwin_framework|darwin_framework_skip)
+ test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ prev=
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+ continue
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: more than one -exported-symbols argument is not allowed"
+ exit $EXIT_FAILURE
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework|-arch|-isysroot)
+ case " $CC " in
+ *" ${arg} ${1} "* | *" ${arg} ${1} "*)
+ prev=darwin_framework_skip ;;
+ *) compiler_flags="$compiler_flags $arg"
+ prev=darwin_framework ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ notinst_path="$notinst_path $dir"
+ fi
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs -framework System"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ -model)
+ compile_command="$compile_command $arg"
+ compiler_flags="$compiler_flags $arg"
+ finalize_command="$finalize_command $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ compiler_flags="$compiler_flags $arg"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+ # -r[0-9][0-9]* specifies the processor on the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+ # +DA*, +DD* enable 64-bit mode on the HP compiler
+ # -q* pass through compiler args for the IBM compiler
+ # -m* pass through architecture-specific compiler args for GCC
+ # -m*, -t[45]*, -txscale* pass through architecture-specific
+ # compiler args for GCC
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # @file GCC response files
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
+
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ compiler_flags="$compiler_flags $arg"
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+ $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Wl,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $wl$flag"
+ linker_flags="$linker_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit $EXIT_FAILURE
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+ done # argument parsing loop
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+ # Create the object directory.
+ if test ! -d "$output_objdir"; then
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then
+ exit $exit_status
+ fi
+ fi
+
+ # Determine the type of output
+ case $output in
+ "")
+ $echo "$modename: you must specify an output file" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ case $host in
+ *cygwin* | *mingw* | *pw32*)
+ # don't eliminate duplications in $postdeps and $predeps
+ duplicate_compiler_generated_deps=yes
+ ;;
+ *)
+ duplicate_compiler_generated_deps=$duplicate_deps
+ ;;
+ esac
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ case $linkmode in
+ lib)
+ passes="conv link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+ for pass in $passes; do
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags $deplib"
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+ continue
+ fi
+ name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+ for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if (${SED} -e '2q' $lib |
+ grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ library_names=
+ old_library=
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ *)
+ $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ if eval $echo \"$deplib\" 2>/dev/null \
+ | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
+ $echo
+ $echo "*** Warning: Trying to link with static lib archive $deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because the file extensions .$libext of this argument makes me believe"
+ $echo "*** that it is just a static archive that I should not used here."
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the"
+ $echo "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ $echo "$modename: \`$lib' is not a convenience library" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ $echo "$modename: warning: library \`$lib' was moved." 1>&2
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi
+ fi # $installed = yes
+ name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { { test "$prefer_static_libs" = no ||
+ test "$prefer_static_libs,$installed" = "built,yes"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath " in
+ *" $dir "*) ;;
+ *" $absdir "*) ;;
+ *) temp_rpath="$temp_rpath $absdir" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes ; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on
+ # some systems (darwin)
+ if test "$shouldnotlink" = yes && test "$pass" = link ; then
+ $echo
+ if test "$linkmode" = prog; then
+ $echo "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $echo "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $echo "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+ libname=`eval \\$echo \"$libname_spec\"`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw*)
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+ newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ $show "extracting exported symbol list from \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$extract_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ $show "generating import library for \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$old_archive_from_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a module then we can not link against
+ # it, someone is ignoring the new warnings I added
+ if /usr/bin/file -L $add 2> /dev/null |
+ $EGREP ": [^:]* bundle" >/dev/null ; then
+ $echo "** Warning, lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ $echo
+ $echo "** And there doesn't seem to be a static archive available"
+ $echo "** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ $echo "$modename: configuration error: unsupported hardcode properties"
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes && \
+ test "$hardcode_minus_L" != yes && \
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ $echo
+ $echo "*** Warning: This system can not link to static lib archive $lib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ $echo "*** But as you try to build a module library, libtool will still create "
+ $echo "*** a static module, that should work as long as the dlopening application"
+ $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$deplib" && dir="."
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if grep "^installed=no" $deplib > /dev/null; then
+ path="$absdir/$objdir"
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test "$absdir" != "$libdir"; then
+ $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+ fi
+ path="$absdir"
+ fi
+ depdepl=
+ case $host in
+ *-*-darwin*)
+ # we do not want to link against static libs,
+ # but need to link against shared
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$path/$depdepl" ; then
+ depdepl="$path/$depdepl"
+ fi
+ # do not add paths which are already there
+ case " $newlib_search_path " in
+ *" $path "*) ;;
+ *) newlib_search_path="$newlib_search_path $path";;
+ esac
+ fi
+ path=""
+ ;;
+ *)
+ path="-L$path"
+ ;;
+ esac
+ ;;
+ -l*)
+ case $host in
+ *-*-darwin*)
+ # Again, we only want to link against shared libraries
+ eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+ for tmp in $newlib_search_path ; do
+ if test -f "$tmp/lib$tmp_libs.dylib" ; then
+ eval depdepl="$tmp/lib$tmp_libs.dylib"
+ break
+ fi
+ done
+ path=""
+ ;;
+ *) continue ;;
+ esac
+ ;;
+ *) continue ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ case " $deplibs " in
+ *" $depdepl "*) ;;
+ *) deplibs="$depdepl $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+ fi
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ if test "$module" = no; then
+ $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+ exit $EXIT_FAILURE
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the non-libtool"
+ $echo "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ if test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+ fi
+
+ set dummy $rpath
+ if test "$#" -gt 2; then
+ $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+ fi
+ install_libdir="$2"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+ fi
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ IFS="$save_ifs"
+
+ if test -n "$8"; then
+ $echo "$modename: too many parameters to \`-version-info'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$2"
+ number_minor="$3"
+ number_revision="$4"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows|none)
+ current=`expr $number_major + $number_minor`
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ current=`expr $number_major + $number_minor`
+ age="$number_minor"
+ revision="$number_minor"
+ lt_irix_increment=no
+ ;;
+ esac
+ ;;
+ no)
+ current="$2"
+ revision="$3"
+ age="$4"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ minor_current=`expr $current + 1`
+ xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current";
+ ;;
+
+ irix | nonstopux)
+ if test "X$lt_irix_increment" = "Xno"; then
+ major=`expr $current - $age`
+ else
+ major=`expr $current - $age + 1`
+ fi
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ iface=`expr $revision - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ major=.`expr $current - $age`
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ iface=`expr $current - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+ fi
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$echo "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ if test -n "$removelist"; then
+ $show "${rm}r $removelist"
+ $run ${rm}r $removelist
+ fi
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"`
+ # deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"`
+ # dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs -framework System"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $rm conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $rm conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ name=`expr $i : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which I believe you do not have"
+ $echo "*** because a test_compile did reveal that the linker did not use it for"
+ $echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ name=`expr $i : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ $rm conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because a test_compile did reveal that the linker did not use this one"
+ $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning! Library $i is needed by this library but I was not able to"
+ $echo "*** make it link in! You will probably need to install it or some"
+ $echo "*** library that it depends on before this library will be fully"
+ $echo "*** functional. Installing it before continuing would be even better."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method
+ file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name=`expr $a_deplib : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null \
+ | grep " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name=`expr $a_deplib : '-l\(.*\)'`
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval $echo \"$potent_lib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+ -e 's/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+ done
+ fi
+ if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \
+ | grep . >/dev/null; then
+ $echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ $echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ $echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ $echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ $echo
+ $echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $echo "*** dependencies of module $libname. Therefore, libtool will create"
+ $echo "*** a static module, that should work as long as the dlopening"
+ $echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ $echo "*** The inter-library dependencies that have been dropped here will be"
+ $echo "*** automatically added whenever a program is linked with this library"
+ $echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ $echo
+ $echo "*** Since this library must not contain undefined symbols,"
+ $echo "*** because either the platform does not support them or"
+ $echo "*** it was explicitly requested with -no-undefined,"
+ $echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ case $archive_cmds in
+ *\$LD*) eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" ;;
+ *) eval dep_rpath=\"$hardcode_libdir_flag_spec\" ;;
+ esac
+ else
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ linknames=
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ if len=`expr "X$cmd" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ $show "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex"; then
+ $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+ $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+ $run eval '$mv "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ libobjs="$libobjs $func_extract_archives_result"
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" &&
+ len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise.
+ $echo "creating reloadable object files..."
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ output_la=`$echo "X$output" | $Xsed -e "$basename"`
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ delfiles=
+ last_robj=
+ k=1
+ output=$output_objdir/$output_la-${k}.$objext
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+ if test "X$objlist" = X ||
+ { len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+ test "$len" -le "$max_cmd_len"; }; then
+ objlist="$objlist $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-${k}.$objext
+ k=`expr $k + 1`
+ output=$output_objdir/$output_la-${k}.$objext
+ objlist=$obj
+ len=1
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+ if ${skipped_export-false}; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+ fi
+
+ # Set up a command to remove the reloadable object files
+ # after they are used.
+ i=0
+ while test "$i" -lt "$k"
+ do
+ i=`expr $i + 1`
+ delfiles="$delfiles $output_objdir/$output_la-${i}.$objext"
+ done
+
+ $echo "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+
+ # Append the command to remove the reloadable object files
+ # to the just-reset $cmds.
+ eval cmds=\"\$cmds~\$rm $delfiles\"
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+ fi
+
+ case $output in
+ *.lo)
+ if test -n "$objs$old_deplibs"; then
+ $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ libobj="$output"
+ obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $run $rm $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec and hope we can get by with
+ # turning comma into space..
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ reload_conv_objs=$reload_objs\ `$echo "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'`
+ else
+ gentop="$output_objdir/${obj}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $run eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+ esac
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+ fi
+
+ if test "$preload" = yes; then
+ if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+ test "$dlopen_self_static" = unknown; then
+ $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+ fi
+ fi
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ case $host in
+ *darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ if test "$tagname" = CXX ; then
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ fi
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ fi
+
+ dlsyms=
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ dlsyms="${outputname}S.c"
+ else
+ $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+ fi
+ fi
+
+ if test -n "$dlsyms"; then
+ case $dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${outputname}.nm"
+
+ $show "$rm $nlist ${nlist}S ${nlist}T"
+ $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+ # Parse the name list into a source file.
+ $show "creating $output_objdir/$dlsyms"
+
+ test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ $show "generating symbol list for \`$output'"
+
+ test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ for arg in $progfiles; do
+ $show "extracting global C symbols from \`$arg'"
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$outputname.exp"
+ $run $rm $export_symbols
+ $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* )
+ $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ else
+ $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ $run eval 'mv "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* )
+ $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ fi
+ fi
+
+ for arg in $dlprefiles; do
+ $show "extracting global C symbols from \`$arg'"
+ name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+ $run eval '$echo ": $name " >> "$nlist"'
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -z "$run"; then
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $mv "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if grep -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ grep -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+ else
+ $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+ fi
+
+ $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+"
+
+ case $host in
+ *cygwin* | *mingw* )
+ $echo >> "$output_objdir/$dlsyms" "\
+/* DATA imports from DLLs on WIN32 can't be const, because
+ runtime relocations are performed -- see ld's documentation
+ on pseudo-relocs */
+struct {
+"
+ ;;
+ * )
+ $echo >> "$output_objdir/$dlsyms" "\
+const struct {
+"
+ ;;
+ esac
+
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ const char *name;
+ lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ fi
+
+ pic_flag_for_symtable=
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+ esac;;
+ *-*-hpux*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag";;
+ esac
+ esac
+
+ # Now compile the dynamic symbol file.
+ $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+ # Clean up the generated files.
+ $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+ $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+ # Transform the symbol file into the correct name.
+ case $host in
+ *cygwin* | *mingw* )
+ if test -f "$output_objdir/${outputname}.def" ; then
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP`
+ else
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+ fi
+ ;;
+ * )
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+ ;;
+ esac
+ ;;
+ *)
+ $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP`
+ fi
+
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ # Replace the output file specification.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$output"'%g' | $NL2SP`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ $show "$link_command"
+ $run eval "$link_command"
+ exit_status=$?
+
+ # Delete the generated files.
+ if test -n "$dlsyms"; then
+ $show "$rm $output_objdir/${outputname}S.${objext}"
+ $run $rm "$output_objdir/${outputname}S.${objext}"
+ fi
+
+ exit $exit_status
+ fi
+
+ if test -n "$shlibpath_var"; then
+ # We should set the shlibpath_var
+ rpath=
+ for dir in $temp_rpath; do
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*)
+ # Absolute path.
+ rpath="$rpath$dir:"
+ ;;
+ *)
+ # Relative path: add a thisdir entry.
+ rpath="$rpath\$thisdir/$dir:"
+ ;;
+ esac
+ done
+ temp_rpath="$rpath"
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $run $rm $output
+ # Link the executable and exit
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+ $echo "$modename: \`$output' will be relinked during installation" 1>&2
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $SP2NL | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g' | $NL2SP`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+
+ # Now create the wrapper script.
+ $show "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP`
+ fi
+
+ # Quote $echo for shipping.
+ if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
+ case $progpath in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+ esac
+ qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if our run command is non-null.
+ if test -z "$run"; then
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ output_name=`basename $output`
+ output_path=`dirname $output`
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $rm $cwrappersource $cwrapper
+ trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ cat > $cwrappersource <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+
+ Currently, it simply execs the wrapper *script* "/bin/sh $output",
+ but could eventually absorb all of the scripts functionality and
+ exec $objdir/$outputname directly.
+*/
+EOF
+ cat >> $cwrappersource<<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+/* -DDEBUG is fairly common in CFLAGS. */
+#undef DEBUG
+#if defined DEBUGWRAPPER
+# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__)
+#else
+# define DEBUG(format, ...)
+#endif
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+const char * base_name (const char *name);
+char * find_executable(const char *wrapper);
+int check_executable(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ DEBUG("(main) argv[0] : %s\n",argv[0]);
+ DEBUG("(main) program_name : %s\n",program_name);
+ newargz = XMALLOC(char *, argc+2);
+EOF
+
+ cat >> $cwrappersource <<EOF
+ newargz[0] = (char *) xstrdup("$SHELL");
+EOF
+
+ cat >> $cwrappersource <<"EOF"
+ newargz[1] = find_executable(argv[0]);
+ if (newargz[1] == NULL)
+ lt_fatal("Couldn't find %s", argv[0]);
+ DEBUG("(main) found exe at : %s\n",newargz[1]);
+ /* we know the script has the same name, without the .exe */
+ /* so make sure newargz[1] doesn't end in .exe */
+ strendzap(newargz[1],".exe");
+ for (i = 1; i < argc; i++)
+ newargz[i+1] = xstrdup(argv[i]);
+ newargz[argc+1] = NULL;
+
+ for (i=0; i<argc+1; i++)
+ {
+ DEBUG("(main) newargz[%d] : %s\n",i,newargz[i]);
+ ;
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat >> $cwrappersource <<EOF
+ execv("$SHELL",(char const **)newargz);
+EOF
+ ;;
+ *)
+ cat >> $cwrappersource <<EOF
+ execv("$SHELL",newargz);
+EOF
+ ;;
+ esac
+
+ cat >> $cwrappersource <<"EOF"
+ return 127;
+}
+
+void *
+xmalloc (size_t num)
+{
+ void * p = (void *) malloc (num);
+ if (!p)
+ lt_fatal ("Memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char)name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable(const char * path)
+{
+ struct stat st;
+
+ DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!");
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0) &&
+ (
+ /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */
+#if defined (S_IXOTH)
+ ((st.st_mode & S_IXOTH) == S_IXOTH) ||
+#endif
+#if defined (S_IXGRP)
+ ((st.st_mode & S_IXGRP) == S_IXGRP) ||
+#endif
+ ((st.st_mode & S_IXUSR) == S_IXUSR))
+ )
+ return 1;
+ else
+ return 0;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise */
+char *
+find_executable (const char* wrapper)
+{
+ int has_slash = 0;
+ const char* p;
+ const char* p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char* concat_name;
+
+ DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!");
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char* path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char* q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR(*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen(tmp);
+ concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen(tmp);
+ concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable(concat_name))
+ return concat_name;
+ XFREE(concat_name);
+ return NULL;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert(str != NULL);
+ assert(pat != NULL);
+
+ len = strlen(str);
+ patlen = strlen(pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp(str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+ const char * message, va_list ap)
+{
+ fprintf (stderr, "%s: %s: ", program_name, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+ va_end (ap);
+}
+EOF
+ # we should really use a build-platform specific compiler
+ # here, but OTOH, the wrappers (shell script and this C one)
+ # are only useful if you want to execute the "real" binary.
+ # Since the "real" binary is built for $host, then this
+ # wrapper might as well be built for $host, too.
+ $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource
+ ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
+
+ $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE).
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variable:
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$echo are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ echo=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$echo works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$echo will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $echo >> $output "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+ done
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $echo >> $output "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" || \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $mkdir \"\$progdir\"
+ else
+ $rm \"\$progdir/\$file\"
+ fi"
+
+ $echo >> $output "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $echo \"\$relink_command_output\" >&2
+ $rm \"\$progdir/\$file\"
+ exit $EXIT_FAILURE
+ fi
+ fi
+
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $rm \"\$progdir/\$program\";
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $rm \"\$progdir/\$file\"
+ fi"
+ else
+ $echo >> $output "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $echo >> $output "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $echo >> $output "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $echo >> $output "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $echo >> $output "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2*)
+ $echo >> $output "\
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $echo >> $output "\
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $echo >> $output "\
+ \$echo \"\$0: cannot exec \$program \$*\"
+ exit $EXIT_FAILURE
+ fi
+ else
+ # The program doesn't exist.
+ \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$echo \"This script is just a wrapper for \$program.\" 1>&2
+ $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit $EXIT_FAILURE
+ fi
+fi\
+"
+ chmod +x $output
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $addlibs
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ $echo "X$obj" | $Xsed -e 's%^.*/%%'
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "copying selected object files to avoid basename conflicts..."
+
+ if test -z "$gentop"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ exit_status=$?
+ if test "$exit_status" -ne 0 && test ! -d "$gentop"; then
+ exit $exit_status
+ fi
+ fi
+
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ counter=`expr $counter + 1`
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ $run ln "$obj" "$gentop/$newobj" ||
+ $run cp "$obj" "$gentop/$newobj"
+ oldobjs="$oldobjs $gentop/$newobj"
+ ;;
+ *) oldobjs="$oldobjs $obj" ;;
+ esac
+ done
+ fi
+
+ eval cmds=\"$old_archive_cmds\"
+
+ if len=`expr "X$cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ $echo "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ for obj in $save_oldobjs
+ do
+ oldobjs="$objlist $obj"
+ objlist="$objlist $obj"
+ eval test_cmds=\"$old_archive_cmds\"
+ if len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+ test "$len" -le "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ eval cmd=\"$cmd\"
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$generated"; then
+ $show "${rm}r$generated"
+ $run ${rm}r$generated
+ fi
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ $show "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+
+ # Only create the output if not a dry run.
+ if test -z "$run"; then
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+ for lib in $dlfiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdlfiles="$newdlfiles $libdir/$name"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlfiles="$newdlfiles $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlprefiles="$newdlprefiles $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $rm $output
+ # place dlname in correct position for cygwin
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+ esac
+ $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $echo >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ fi
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+ $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool install mode
+ install)
+ modename="$modename: install"
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ $echo "X$nonopt" | grep shtool > /dev/null; then
+ # Aesthetically quote it.
+ arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$arg "
+ arg="$1"
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog$arg"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f)
+ case " $install_prog " in
+ *[\\\ /]cp\ *) ;;
+ *) prev=$arg ;;
+ esac
+ ;;
+ -g | -m | -o) prev=$arg ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog $arg"
+ done
+
+ if test -z "$install_prog"; then
+ $echo "$modename: you must specify an install program" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prev' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ $echo "$modename: no file or destination specified" 1>&2
+ else
+ $echo "$modename: you must specify a destination" 1>&2
+ fi
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Strip any trailing slash from the destination.
+ dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$destdir" = "X$dest" && destdir=.
+ destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files
+ if test "$#" -gt 2; then
+ $echo "$modename: \`$dest' is not a directory" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ library_names=
+ old_library=
+ relink_command=
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+ test "X$dir" = "X$file/" && dir=
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ if test "$inst_prefix_dir" = "$destdir"; then
+ $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%" | $NL2SP`
+ else
+ relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP`
+ fi
+
+ $echo "$modename: warning: relinking \`$file'" 1>&2
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names
+ if test -n "$2"; then
+ realname="$2"
+ shift
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ $show "$install_prog $dir/$srcname $destdir/$realname"
+ $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$striplib $destdir/$realname"
+ $run eval "$striplib $destdir/$realname" || exit $?
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ if test "$linkname" != "$realname"; then
+ $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
+ $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
+ fi
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ cmds=$postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Install the pseudo-library for information purposes.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ instname="$dir/$name"i
+ $show "$install_prog $instname $destdir/$name"
+ $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ if test -n "$destfile"; then
+ $show "$install_prog $file $destfile"
+ $run eval "$install_prog $file $destfile" || exit $?
+ fi
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+ $show "$install_prog $staticobj $staticdest"
+ $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin*|*mingw*)
+ wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+ notinst_deplibs=
+ relink_command=
+
+ # Note that it is not necessary on cygwin/mingw to append a dot to
+ # foo even if both foo and FILE.exe exist: automatic-append-.exe
+ # behavior happens only for exec(3), not for open(2)! Also, sourcing
+ # `FILE.' does not work on cygwin managed mounts.
+ #
+ # If there is no directory component, then add one.
+ case $wrapper in
+ */* | *\\*) . ${wrapper} ;;
+ *) . ./${wrapper} ;;
+ esac
+
+ # Check the variables that should have been set.
+ if test -z "$notinst_deplibs"; then
+ $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ # If there is no directory component, then add one.
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ fi
+ libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ # Note that it is not necessary on cygwin/mingw to append a dot to
+ # foo even if both foo and FILE.exe exist: automatic-append-.exe
+ # behavior happens only for exec(3), not for open(2)! Also, sourcing
+ # `FILE.' does not work on cygwin managed mounts.
+ #
+ # If there is no directory component, then add one.
+ case $wrapper in
+ */* | *\\*) . ${wrapper} ;;
+ *) . ./${wrapper} ;;
+ esac
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ if test "$finalize" = yes && test -z "$run"; then
+ tmpdir=`func_mktempdir`
+ file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g' | $NL2SP`
+
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ ${rm}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ $echo "$modename: warning: cannot relink \`$file'" 1>&2
+ fi
+ else
+ # Install the binary that we compiled earlier.
+ file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+ ;;
+ esac
+ ;;
+ esac
+ $show "$install_prog$stripme $file $destfile"
+ $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+ test -n "$outputname" && ${rm}r "$tmpdir"
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ $show "$install_prog $file $oldlib"
+ $run eval "$install_prog \$file \$oldlib" || exit $?
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ $show "$old_striplib $oldlib"
+ $run eval "$old_striplib $oldlib" || exit $?
+ fi
+
+ # Do each command in the postinstall commands.
+ cmds=$old_postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$future_libdirs"; then
+ $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+ fi
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ test -n "$run" && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+ ;;
+
+ # libtool finish mode
+ finish)
+ modename="$modename: finish"
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ cmds=$finish_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || admincmds="$admincmds
+ $cmd"
+ done
+ IFS="$save_ifs"
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $run eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ test "$show" = : && exit $EXIT_SUCCESS
+
+ $echo "X----------------------------------------------------------------------" | $Xsed
+ $echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $echo " $libdir"
+ done
+ $echo
+ $echo "If you ever happen to want to link against installed libraries"
+ $echo "in a given directory, LIBDIR, you must either use libtool, and"
+ $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ $echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ $echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ $echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ $echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ $echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $echo " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $echo " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ $echo
+ $echo "See any operating system documentation about shared libraries for"
+ $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ $echo "X----------------------------------------------------------------------" | $Xsed
+ exit $EXIT_SUCCESS
+ ;;
+
+ # libtool execute mode
+ execute)
+ modename="$modename: execute"
+
+ # The first argument is the command name.
+ cmd="$nonopt"
+ if test -z "$cmd"; then
+ $echo "$modename: you must specify a COMMAND" 1>&2
+ $echo "$help"
+ exit $EXIT_FAILURE
+ fi
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ if test ! -f "$file"; then
+ $echo "$modename: \`$file' is not a file" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+ exit $EXIT_FAILURE
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ ;;
+
+ *)
+ $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+ args="$args \"$file\""
+ done
+
+ if test -z "$run"; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+ $echo "export $shlibpath_var"
+ fi
+ $echo "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+ ;;
+
+ # libtool clean and uninstall mode
+ clean | uninstall)
+ modename="$modename: $mode"
+ rm="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) rm="$rm $arg"; rmforce=yes ;;
+ -*) rm="$rm $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ if test -z "$rm"; then
+ $echo "$modename: you must specify an RM program" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$file"; then
+ dir=.
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if (test -L "$file") >/dev/null 2>&1 \
+ || (test -h "$file") >/dev/null 2>&1 \
+ || test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ . $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+ case "$mode" in
+ clean)
+ case " $library_names " in
+ # " " in the beginning catches empty $dlname
+ *" $dlname "*) ;;
+ *) rmfiles="$rmfiles $objdir/$dlname" ;;
+ esac
+ test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ cmds=$postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ cmds=$old_postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+ # Read the .lo file
+ . $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" \
+ && test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" \
+ && test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ noexename=`$echo $name|${SED} 's,.exe$,,'`
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ relink_command=
+ . $dir/$noexename
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles || exit_status=1
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ $show "rmdir $dir"
+ $run rmdir $dir >/dev/null 2>&1
+ fi
+ done
+
+ exit $exit_status
+ ;;
+
+ "")
+ $echo "$modename: you must specify a MODE" 1>&2
+ $echo "$generic_help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+ esac
+
+ if test -z "$exec_cmd"; then
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$generic_help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+ eval exec $exec_cmd
+ exit $EXIT_FAILURE
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+-n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --finish same as \`--mode=finish'
+ --help display this help message and exit
+ --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
+ --quiet same as \`--silent'
+ --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ --version print version information
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to <bug-libtool@gnu.org>."
+ exit $EXIT_SUCCESS
+ ;;
+
+clean)
+ $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+compile)
+ $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -static always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+execute)
+ $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+finish)
+ $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+install)
+ $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+link)
+ $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+uninstall)
+ $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+*)
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$help" 1>&2
+ exit $EXIT_FAILURE
+ ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit $?
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+disable_libs=shared
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+disable_libs=static
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/utils/missing b/utils/missing
new file mode 100755
index 00000000..1c8ff704
--- /dev/null
+++ b/utils/missing
@@ -0,0 +1,367 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2006-05-10.23
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case $1 in
+ lex|yacc)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $1 in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '
+ /^@setfilename/{
+ s/.* \([^ ]*\) *$/\1/
+ p
+ q
+ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ tar)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case $firstarg in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case $firstarg in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/utils/network/Makefile.am b/utils/network/Makefile.am
new file mode 100644
index 00000000..15208f5a
--- /dev/null
+++ b/utils/network/Makefile.am
@@ -0,0 +1,24 @@
+
+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 \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -I$(top_srcdir)/sdpd
+
+EXTRA_DIST = network.conf network-api.txt test-network
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/network/Makefile.in b/utils/network/Makefile.in
new file mode 100644
index 00000000..d1ae280e
--- /dev/null
+++ b/utils/network/Makefile.in
@@ -0,0 +1,509 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = network
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(plugindir)"
+pluginLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+network_la_LIBADD =
+am__network_la_SOURCES_DIST = main.c manager.h manager.c server.h \
+ server.c bridge.h bridge.c connection.h connection.c common.h \
+ common.c
+@NETWORKPLUGIN_TRUE@am_network_la_OBJECTS = main.lo manager.lo \
+@NETWORKPLUGIN_TRUE@ server.lo bridge.lo connection.lo \
+@NETWORKPLUGIN_TRUE@ common.lo
+network_la_OBJECTS = $(am_network_la_OBJECTS)
+@NETWORKPLUGIN_TRUE@am_network_la_rpath = -rpath $(plugindir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(network_la_SOURCES)
+DIST_SOURCES = $(am__network_la_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@NETWORKPLUGIN_TRUE@plugindir = $(libdir)/bluetooth/plugins
+@NETWORKPLUGIN_TRUE@plugin_LTLIBRARIES = network.la
+@NETWORKPLUGIN_TRUE@network_la_SOURCES = main.c manager.h manager.c \
+@NETWORKPLUGIN_TRUE@ server.h server.c bridge.h bridge.c \
+@NETWORKPLUGIN_TRUE@ connection.h connection.c common.h common.c
+
+@NETWORKPLUGIN_TRUE@LDADD = $(top_builddir)/common/libhelper.a \
+@NETWORKPLUGIN_TRUE@ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+AM_LDFLAGS = -module -avoid-version -no-undefined \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -I$(top_srcdir)/sdpd
+EXTRA_DIST = network.conf network-api.txt test-network
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu network/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu network/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+network.la: $(network_la_OBJECTS) $(network_la_DEPENDENCIES)
+ $(LINK) $(am_network_la_rpath) $(network_la_OBJECTS) $(network_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bridge.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/network/bridge.c b/utils/network/bridge.c
new file mode 100644
index 00000000..ba59f380
--- /dev/null
+++ b/utils/network/bridge.c
@@ -0,0 +1,148 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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);
+ 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/utils/network/bridge.h b/utils/network/bridge.h
new file mode 100644
index 00000000..13166520
--- /dev/null
+++ b/utils/network/bridge.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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/utils/network/common.c b/utils/network/common.c
new file mode 100644
index 00000000..f1dbe1c5
--- /dev/null
+++ b/utils/network/common.c
@@ -0,0 +1,396 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <net/if.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/bnep.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "common.h"
+#include "textfile.h"
+
+static int ctl;
+static GSList *pids;
+
+#define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb"
+#define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb"
+#define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
+
+static struct {
+ const char *name; /* Friendly name */
+ const char *uuid128; /* UUID 128 */
+ uint16_t id; /* Service class identifier */
+} __svc[] = {
+ { "panu", PANU_UUID, BNEP_SVC_PANU },
+ { "gn", GN_UUID, BNEP_SVC_GN },
+ { "nap", NAP_UUID, BNEP_SVC_NAP },
+ { 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;
+ uint16_t id;
+
+ /* Friendly service name */
+ for (i = 0; __svc[i].name; i++)
+ if (!strcasecmp(svc, __svc[i].name)) {
+ return __svc[i].id;
+ }
+
+ /* UUID 128 string */
+ for (i = 0; __svc[i].uuid128; i++)
+ if (!strcasecmp(svc, __svc[i].uuid128)) {
+ return __svc[i].id;
+ }
+
+ /* Try convert to HEX */
+ id = strtol(svc, NULL, 16);
+ if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN))
+ return 0;
+
+ return id;
+}
+
+const char *bnep_uuid(uint16_t id)
+{
+ int i;
+
+ for (i = 0; __svc[i].uuid128; i++)
+ if (__svc[i].id == id)
+ return __svc[i].uuid128;
+ return NULL;
+}
+
+const char *bnep_name(uint16_t id)
+{
+ int i;
+
+ for (i = 0; __svc[i].name; i++)
+ if (__svc[i].id == id)
+ return __svc[i].name;
+ return NULL;
+}
+
+int bnep_init(const char *panu_script, const char *gn_script,
+ const char *nap_script)
+{
+ ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
+
+ if (ctl < 0) {
+ int err = errno;
+ error("Failed to open control socket: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ panu = panu_script;
+ gn = gn_script;
+ nap = nap_script;
+ return 0;
+}
+
+int bnep_cleanup(void)
+{
+ close(ctl);
+ return 0;
+}
+
+int bnep_kill_connection(bdaddr_t *dst)
+{
+ struct bnep_conndel_req req;
+
+ memset(&req, 0, sizeof(req));
+ baswap((bdaddr_t *)&req.dst, dst);
+ req.flags = 0;
+ if (ioctl(ctl, BNEPCONNDEL, &req)) {
+ int err = errno;
+ error("Failed to kill connection: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+ return 0;
+}
+
+int bnep_kill_all_connections(void)
+{
+ struct bnep_connlist_req req;
+ struct bnep_conninfo ci[7];
+ int i, err;
+
+ memset(&req, 0, sizeof(req));
+ req.cnum = 7;
+ req.ci = ci;
+ if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
+ err = errno;
+ error("Failed to get connection list: %s (%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ for (i=0; i < req.cnum; i++) {
+ struct bnep_conndel_req del;
+
+ memset(&del, 0, sizeof(del));
+ memcpy(del.dst, ci[i].dst, ETH_ALEN);
+ del.flags = 0;
+ ioctl(ctl, BNEPCONNDEL, &del);
+ }
+ return 0;
+}
+
+int bnep_connadd(int sk, uint16_t role, char *dev)
+{
+ struct bnep_connadd_req req;
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.device, dev, 16);
+ req.device[15] = '\0';
+ req.sock = sk;
+ req.role = role;
+ if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
+ int err = errno;
+ error("Failed to add device %s: %s(%d)",
+ dev, strerror(err), err);
+ return -err;
+ }
+
+ strncpy(dev, req.device, 16);
+ return 0;
+}
+
+static void bnep_setup(gpointer data)
+{
+}
+
+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;
+
+ /* Check if a script is running */
+ l = g_slist_find_custom(pids, devname, find_devname);
+ if (l) {
+ bnep = l->data;
+
+ 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_INET6, SOCK_DGRAM, 0);
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, devname);
+
+ 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;
+ }
+
+ 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;
+}
+
+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];
+
+ l = g_slist_find_custom(pids, devname, find_devname);
+ if (!l)
+ return 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_INET6, SOCK_DGRAM, 0);
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, devname);
+
+ ifr.ifr_flags &= ~IFF_UP;
+
+ /* Bring down the interface */
+ ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr);
+
+ pids = g_slist_remove(pids, bnep);
+
+ if (bnep->devname)
+ g_free(bnep->devname);
+
+ if (bnep->script)
+ g_free(bnep->script);
+
+ g_free(bnep);
+
+ return 0;
+}
+
+int read_remote_name(bdaddr_t *src, bdaddr_t *dst, char *buf, size_t size)
+{
+ char filename[PATH_MAX + 1], addr[18], *str;
+
+ ba2str(src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "names");
+
+ ba2str(dst, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -ENOENT;
+
+ snprintf(buf, size, "%s", str);
+ free(str);
+
+ return 0;
+}
diff --git a/utils/network/common.h b/utils/network/common.h
new file mode 100644
index 00000000..e6aa90f6
--- /dev/null
+++ b/utils/network/common.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define MAX_PATH_LENGTH 64 /* D-Bus path */
+#define NETWORK_PATH "/org/bluez/network"
+
+int bnep_init(const char *panu_script, const char *gn_script,
+ const char *nap_script);
+int bnep_cleanup(void);
+
+uint16_t bnep_service_id(const char *svc);
+const char *bnep_uuid(uint16_t id);
+const char *bnep_name(uint16_t id);
+
+int bnep_kill_connection(bdaddr_t *dst);
+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_down(const char *devname);
+
+int read_remote_name(bdaddr_t *src, bdaddr_t *dst, char *buf, size_t size);
diff --git a/utils/network/connection.c b/utils/network/connection.c
new file mode 100644
index 00000000..d2fd85c2
--- /dev/null
+++ b/utils/network/connection.c
@@ -0,0 +1,719 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/bnep.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "../hcid/dbus-common.h"
+
+#include "logging.h"
+#include "textfile.h"
+#include "glib-helper.h"
+
+#include "error.h"
+#include "common.h"
+#include "connection.h"
+
+typedef enum {
+ CONNECTED,
+ CONNECTING,
+ DISCONNECTED
+} conn_state;
+
+struct network_conn {
+ DBusMessage *msg;
+ bdaddr_t store;
+ bdaddr_t src;
+ bdaddr_t dst;
+ char *path; /* D-Bus path */
+ char dev[16]; /* Interface name */
+ char *name; /* Service Name */
+ char *desc; /* Service Description*/
+ uint16_t id; /* Role: Service Class Identifier */
+ conn_state state;
+ int sk;
+};
+
+struct __service_16 {
+ uint16_t dst;
+ uint16_t src;
+} __attribute__ ((packed));
+
+static DBusConnection *connection = NULL;
+static const char *prefix = NULL;
+static GSList *connections = NULL;
+
+gint find_connection(gconstpointer a, gconstpointer b)
+{
+ const struct network_conn *nc = a;
+ const char *path = b;
+
+ return strcmp(nc->path, path);
+}
+
+static inline DBusMessage *not_supported(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Not suported");
+}
+
+static inline DBusMessage *already_connected(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Device already connected");
+}
+
+static inline DBusMessage *not_connected(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Device not connected");
+}
+
+static inline DBusMessage *no_pending_connect(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Device has no pending connect");
+}
+
+static inline DBusMessage *connection_attempt_failed(DBusMessage *msg, int err)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed",
+ err ? strerror(err) : "Connection attempt failed");
+}
+
+static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct network_conn *nc = data;
+
+ if (connection != NULL) {
+ g_dbus_emit_signal(connection, nc->path,
+ NETWORK_CONNECTION_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+ }
+
+ info("%s disconnected", nc->dev);
+
+ bnep_if_down(nc->dev);
+ nc->state = DISCONNECTED;
+ memset(nc->dev, 0, 16);
+ strncpy(nc->dev, prefix, strlen(prefix));
+ g_io_channel_close(chan);
+
+ return FALSE;
+}
+
+static gboolean bnep_connect_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct network_conn *nc = data;
+ struct bnep_control_rsp *rsp;
+ char pkt[BNEP_MTU];
+ gsize r;
+ int sk;
+ DBusMessage *reply;
+ const char *pdev;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ error("Hangup or error on l2cap server socket");
+ goto failed;
+ }
+
+ memset(pkt, 0, BNEP_MTU);
+ if (g_io_channel_read(chan, pkt, sizeof(pkt) - 1,
+ &r) != G_IO_ERROR_NONE) {
+ error("IO Channel read error");
+ goto failed;
+ }
+
+ if (r <= 0) {
+ error("No packet received on l2cap socket");
+ goto failed;
+ }
+
+ errno = EPROTO;
+
+ if (r < sizeof(*rsp)) {
+ error("Packet received is not bnep type");
+ goto failed;
+ }
+
+ rsp = (void *) pkt;
+ if (rsp->type != BNEP_CONTROL) {
+ error("Packet received is not bnep type");
+ goto failed;
+ }
+
+ if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
+ return TRUE;
+
+ r = ntohs(rsp->resp);
+
+ if (r != BNEP_SUCCESS) {
+ error("bnep failed");
+ goto failed;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ if (bnep_connadd(sk, BNEP_SVC_PANU, nc->dev)) {
+ error("%s could not be added", nc->dev);
+ goto failed;
+ }
+
+ bnep_if_up(nc->dev, nc->id);
+ g_dbus_emit_signal(connection, nc->path,
+ NETWORK_CONNECTION_INTERFACE,
+ "Connected",
+ DBUS_TYPE_INVALID);
+
+ pdev = nc->dev;
+
+ reply = g_dbus_create_reply(nc->msg, DBUS_TYPE_STRING, &pdev,
+ DBUS_TYPE_INVALID);
+ g_dbus_send_message(connection, reply);
+
+ nc->state = CONNECTED;
+
+ info("%s connected", nc->dev);
+ /* Start watchdog */
+ g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) bnep_watchdog_cb, nc);
+ return FALSE;
+
+failed:
+ if (nc->state != DISCONNECTED) {
+ nc->state = DISCONNECTED;
+ reply = connection_attempt_failed(nc->msg, EIO);
+ g_dbus_send_message(connection, reply);
+ g_io_channel_close(chan);
+ }
+
+ return FALSE;
+}
+
+static int bnep_connect(struct network_conn *nc)
+{
+ struct bnep_setup_conn_req *req;
+ struct __service_16 *s;
+ unsigned char pkt[BNEP_MTU];
+ GIOChannel *io;
+ int err = 0;
+
+ /* Send request */
+ req = (void *) pkt;
+ req->type = BNEP_CONTROL;
+ req->ctrl = BNEP_SETUP_CONN_REQ;
+ req->uuid_size = 2; /* 16bit UUID */
+ s = (void *) req->service;
+ s->dst = htons(nc->id);
+ s->src = htons(BNEP_SVC_PANU);
+
+ io = g_io_channel_unix_new(nc->sk);
+ g_io_channel_set_close_on_unref(io, FALSE);
+
+ if (send(nc->sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0) {
+ err = -errno;
+ goto out;
+ }
+
+ g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) bnep_connect_cb, nc);
+
+out:
+ g_io_channel_unref(io);
+ return err;
+}
+
+static void connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer data)
+{
+ struct network_conn *nc = data;
+ DBusMessage *reply;
+
+ if (err < 0) {
+ error("l2cap connect(): %s (%d)", strerror(-err), -err);
+ goto failed;
+ }
+
+ nc->sk = g_io_channel_unix_get_fd(chan);
+
+ err = bnep_connect(nc);
+ if (err < 0) {
+ error("bnep connect(): %s (%d)", strerror(-err), -err);
+ g_io_channel_close(chan);
+ g_io_channel_unref(chan);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ nc->state = DISCONNECTED;
+
+ reply = connection_attempt_failed(nc->msg, -err);
+ g_dbus_send_message(connection, reply);
+}
+
+static DBusMessage *get_adapter(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct network_conn *nc = data;
+ char addr[18];
+ const char *paddr = addr;
+
+ ba2str(&nc->src, addr);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *get_address(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct network_conn *nc = data;
+ char addr[18];
+ const char *paddr = addr;
+
+ ba2str(&nc->dst, addr);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *get_uuid(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+ const char *uuid;
+
+ uuid = bnep_uuid(nc->id);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *get_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+
+ if (!nc->name)
+ return not_supported(msg);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &nc->name,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *get_description(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+
+ if (!nc->desc)
+ return not_supported(msg);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &nc->desc,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *get_interface(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+ const char *pdev = nc->dev;
+
+ if (nc->state != CONNECTED)
+ return not_connected(msg);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &pdev,
+ DBUS_TYPE_INVALID);
+}
+
+/* Connect and initiate BNEP session */
+static DBusMessage *connection_connect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+ int err;
+
+ if (nc->state != DISCONNECTED)
+ return already_connected(msg);
+
+ nc->state = CONNECTING;
+ nc->msg = dbus_message_ref(msg);
+
+ err = bt_l2cap_connect(&nc->src, &nc->dst, BNEP_PSM, BNEP_MTU,
+ connect_cb, nc);
+ if (err < 0) {
+ error("Connect failed. %s(%d)", strerror(errno), errno);
+ dbus_message_unref(nc->msg);
+ nc->msg = NULL;
+ nc->state = DISCONNECTED;
+ return connection_attempt_failed(msg, -err);
+ }
+
+ return NULL;
+}
+
+static DBusMessage *connection_cancel(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+
+ if (nc->state != CONNECTING)
+ return no_pending_connect(msg);
+
+ close(nc->sk);
+ nc->state = DISCONNECTED;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *connection_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+
+ if (nc->state != CONNECTED)
+ return not_connected(msg);
+
+ bnep_if_down(nc->dev);
+ bnep_kill_connection(&nc->dst);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *is_connected(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+ gboolean up = (nc->state == CONNECTED);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_BOOLEAN, &up,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *get_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_conn *nc = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ const char *uuid;
+ char raddr[18];
+ const char *paddr = raddr;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dbus_message_iter_append_dict_entry(&dict, "name",
+ DBUS_TYPE_STRING, &nc->name);
+
+ uuid = bnep_uuid(nc->id);
+ dbus_message_iter_append_dict_entry(&dict, "uuid",
+ DBUS_TYPE_STRING, &uuid);
+
+ ba2str(&nc->dst, raddr);
+ dbus_message_iter_append_dict_entry(&dict, "address",
+ DBUS_TYPE_STRING, &paddr);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static void connection_free(struct network_conn *nc)
+{
+ if (!nc)
+ return;
+
+ if (nc->path)
+ g_free(nc->path);
+
+ if (nc->state == CONNECTED) {
+ bnep_if_down(nc->dev);
+ bnep_kill_connection(&nc->dst);
+ }
+
+ if (nc->name)
+ g_free(nc->name);
+
+ if (nc->desc)
+ g_free(nc->desc);
+
+ g_free(nc);
+ nc = NULL;
+}
+
+static void connection_unregister(void *data)
+{
+ struct network_conn *nc = data;
+
+ info("Unregistered connection path:%s", nc->path);
+
+ connections = g_slist_remove(connections, nc);
+ connection_free(nc);
+}
+
+static GDBusMethodTable connection_methods[] = {
+ { "GetAdapter", "", "s", get_adapter },
+ { "GetAddress", "", "s", get_address },
+ { "GetUUID", "", "s", get_uuid },
+ { "GetName", "", "s", get_name },
+ { "GetDescription", "", "s", get_description },
+ { "GetInterface", "", "s", get_interface },
+ { "Connect", "", "s", connection_connect,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "CancelConnect", "", "", connection_cancel },
+ { "Disconnect", "", "", connection_disconnect },
+ { "IsConnected", "", "b", is_connected },
+ { "GetInfo", "", "a{sv}",get_info },
+ { }
+};
+
+static GDBusSignalTable connection_signals[] = {
+ { "Connected", "" },
+ { "Disconnected", "" },
+ { }
+};
+
+int connection_register(const char *path, bdaddr_t *src, bdaddr_t *dst,
+ uint16_t id, const char *name, const char *desc)
+{
+ struct network_conn *nc;
+ bdaddr_t default_src;
+ int dev_id;
+
+ if (!path)
+ return -EINVAL;
+
+ bacpy(&default_src, BDADDR_ANY);
+ dev_id = hci_get_route(&default_src);
+ if (dev_id < 0 || hci_devba(dev_id, &default_src) < 0)
+ return -1;
+
+ nc = g_new0(struct network_conn, 1);
+
+ if (g_dbus_register_interface(connection, path,
+ NETWORK_CONNECTION_INTERFACE,
+ connection_methods,
+ connection_signals, NULL,
+ nc, connection_unregister) == FALSE) {
+ error("D-Bus failed to register %s interface",
+ NETWORK_CONNECTION_INTERFACE);
+ return -1;
+ }
+
+ nc->path = g_strdup(path);
+ bacpy(&nc->store, src);
+ bacpy(&nc->src, &default_src);
+ bacpy(&nc->dst, dst);
+ nc->id = id;
+ nc->name = g_strdup(name);
+ nc->desc = g_strdup(desc);
+ memset(nc->dev, 0, 16);
+ strncpy(nc->dev, prefix, strlen(prefix));
+ nc->state = DISCONNECTED;
+
+ connections = g_slist_append(connections, nc);
+
+ info("Registered connection path:%s", path);
+
+ return 0;
+}
+
+int connection_store(const char *path, gboolean default_path)
+{
+ struct network_conn *nc;
+ const char *role;
+ char key[32], *value;
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ int len, err;
+ GSList *l;
+
+ l = g_slist_find_custom(connections, path, find_connection);
+ if (!l)
+ return -ENOENT;
+
+ nc = l->data;
+ if (!nc->name || !nc->desc)
+ return -EINVAL;
+
+ /* FIXME: name and desc validation - remove ':' */
+
+ ba2str(&nc->dst, dst_addr);
+ role = bnep_name(nc->id);
+ snprintf(key, 32, "%s#%s", dst_addr, role);
+
+ ba2str(&nc->store, src_addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "network");
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (default_path)
+ err = textfile_put(filename, "default", key);
+ else {
+ len = strlen(nc->name) + strlen(nc->desc) + 2;
+ value = g_malloc0(len);
+ snprintf(value, len, "%s:%s", nc->name, nc->desc);
+ err = textfile_put(filename, key, value);
+ g_free(value);
+ }
+
+ return err;
+}
+
+int connection_find_data(const char *path, const char *pattern)
+{
+ struct network_conn *nc;
+ char addr[18], key[32];
+ const char *role;
+ GSList *l;
+
+ l = g_slist_find_custom(connections, path, find_connection);
+ if (!l)
+ return -1;
+
+ nc = l->data;
+ if (strcasecmp(pattern, nc->dev) == 0)
+ return 0;
+
+ if (strcasecmp(pattern, nc->name) == 0)
+ return 0;
+
+ ba2str(&nc->dst, addr);
+
+ if (strcasecmp(pattern, addr) == 0)
+ return 0;
+
+ role = bnep_name(nc->id);
+ snprintf(key, 32, "%s#%s", addr, role);
+
+ if (strcasecmp(pattern, key) == 0)
+ return 0;
+
+ return -1;
+}
+
+gboolean connection_has_pending(const char *path)
+{
+ struct network_conn *nc;
+ GSList *l;
+
+ l = g_slist_find_custom(connections, path, find_connection);
+ if (!l)
+ return FALSE;
+
+ nc = l->data;
+
+ return (nc->state == CONNECTING);
+}
+
+int connection_remove_stored(const char *path)
+{
+ struct network_conn *nc;
+ const char *role;
+ char key[32];
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ int err;
+ GSList *l;
+
+ l = g_slist_find_custom(connections, path, find_connection);
+ if (!l)
+ return -ENOENT;
+
+ nc = l->data;
+
+ ba2str(&nc->dst, dst_addr);
+ role = bnep_name(nc->id);
+ snprintf(key, 32, "%s#%s", dst_addr, role);
+
+ ba2str(&nc->store, src_addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "network");
+
+ err = textfile_del(filename, key);
+
+ return err;
+}
+
+gboolean connection_is_connected(const char *path)
+{
+ struct network_conn *nc;
+ GSList *l;
+
+ l = g_slist_find_custom(connections, path, find_connection);
+ if (!l)
+ return FALSE;
+
+ nc = l->data;
+
+ return (nc->state == CONNECTED);
+}
+
+int connection_init(DBusConnection *conn, const char *iface_prefix)
+{
+ connection = dbus_connection_ref(conn);
+ prefix = iface_prefix;
+
+ return 0;
+}
+
+void connection_exit()
+{
+ dbus_connection_unref(connection);
+ connection = NULL;
+ prefix = NULL;
+}
diff --git a/utils/network/connection.h b/utils/network/connection.h
new file mode 100644
index 00000000..fd15e816
--- /dev/null
+++ b/utils/network/connection.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define NETWORK_CONNECTION_INTERFACE "org.bluez.network.Connection"
+
+int connection_init(DBusConnection *conn, const char *iface_prefix);
+void connection_exit();
+int connection_register(const char *path, bdaddr_t *src, bdaddr_t *dst,
+ uint16_t id, const char *name, const char *desc);
+int connection_store(const char *path, gboolean default_path);
+int connection_remove_stored(const char *path);
+int connection_find_data(const char *path, const char *pattern);
+gboolean connection_has_pending(const char *path);
+gboolean connection_is_connected(const char *path);
diff --git a/utils/network/main.c b/utils/network/main.c
new file mode 100644
index 00000000..f18223cc
--- /dev/null
+++ b/utils/network/main.c
@@ -0,0 +1,256 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "device.h"
+#include "logging.h"
+#include "manager.h"
+
+#define IFACE_PREFIX "bnep%d"
+#define GN_IFACE "pan0"
+#define NAP_IFACE "pan1"
+
+#define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb"
+#define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb"
+#define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
+
+#define NETWORK_INTERFACE "org.bluez.Network"
+
+static DBusMessage *network_connect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ const char *target, *device = "bnep0";
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &target,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &device,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *network_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable network_methods[] = {
+ { "Connect", "s", "s", network_connect },
+ { "Disconnect", "", "", network_disconnect },
+ { }
+};
+
+static GDBusSignalTable network_signals[] = {
+ { "Connected", "ss" },
+ { "Disconnected", "s" },
+ { }
+};
+
+static DBusConnection *conn;
+
+static int network_probe(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ if (g_dbus_register_interface(conn, device->path, NETWORK_INTERFACE,
+ network_methods, network_signals, NULL,
+ device, NULL) == FALSE)
+ return -1;
+
+ return 0;
+}
+
+static void network_remove(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ g_dbus_unregister_interface(conn, device->path, NETWORK_INTERFACE);
+}
+
+static struct btd_device_driver network_driver = {
+ .name = "network",
+ .uuids = BTD_UUIDS(PANU_UUID, NAP_UUID, GN_UUID),
+ .probe = network_probe,
+ .remove = network_remove,
+};
+
+static struct network_conf conf = {
+ .connection_enabled = TRUE,
+ .server_enabled = TRUE,
+ .iface_prefix = NULL,
+ .panu_script = NULL,
+ .gn_script = NULL,
+ .nap_script = NULL,
+ .gn_iface = NULL,
+ .nap_iface = NULL,
+ .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_error_free(err);
+ goto done;
+ }
+
+ disabled = g_key_file_get_string_list(keyfile, "General",
+ "Disable", NULL, &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ } 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",
+ "DisableSecurity", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+ conf.panu_script = g_key_file_get_string(keyfile, "PANU Role",
+ "Script", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+ conf.gn_script = g_key_file_get_string(keyfile, "GN Role",
+ "Script", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+ conf.nap_script = g_key_file_get_string(keyfile, "NAP Role",
+ "Script", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+ conf.iface_prefix = g_key_file_get_string(keyfile, "PANU Role",
+ "Interface", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+ conf.gn_iface = g_key_file_get_string(keyfile, "GN Role",
+ "Interface", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+ conf.nap_iface = g_key_file_get_string(keyfile, "NAP Role",
+ "Interface", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ }
+
+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");
+}
+
+static int network_init(void)
+{
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (conn == NULL)
+ return -EIO;
+
+ read_config(CONFIGDIR "/network.conf");
+
+ if (network_manager_init(conn, &conf) < 0) {
+ dbus_connection_unref(conn);
+ return -EIO;
+ }
+
+ btd_register_device_driver(&network_driver);
+
+ return 0;
+}
+
+static void network_exit(void)
+{
+ btd_unregister_device_driver(&network_driver);
+
+ network_manager_exit();
+
+ dbus_connection_unref(conn);
+}
+
+BLUETOOTH_PLUGIN_DEFINE("network", network_init, network_exit)
diff --git a/utils/network/manager.c b/utils/network/manager.c
new file mode 100644
index 00000000..dd23b58d
--- /dev/null
+++ b/utils/network/manager.c
@@ -0,0 +1,855 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 <ctype.h>
+#include <dirent.h>
+
+#include <sys/stat.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/bnep.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "logging.h"
+#include "textfile.h"
+#include "glib-helper.h"
+
+#define NETWORK_MANAGER_INTERFACE "org.bluez.network.Manager"
+
+#include "error.h"
+#include "bridge.h"
+#include "manager.h"
+#include "common.h"
+
+#define MAX_NAME_SIZE 256
+
+struct pending_reply {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ bdaddr_t src; /* Source address */
+ bdaddr_t dst; /* Destination address */
+ char *addr; /* Destination address */
+ char *path; /* D-Bus object path */
+ char *adapter_path; /* Default adapter path */
+ uint16_t id; /* Role */
+};
+
+static struct network_conf *conf = NULL;/* Network service configuration */
+static GSList *server_paths = NULL; /* Network registered servers paths */
+static GSList *connection_paths = NULL; /* Network registered connections paths */
+static int default_index = -1; /* Network default connection path index */
+static int net_uid = 0; /* Network objects identifier */
+
+static DBusConnection *connection = NULL;
+
+static void pending_reply_free(struct pending_reply *pr)
+{
+ if (pr->addr)
+ g_free(pr->addr);
+ if (pr->path)
+ g_free(pr->path);
+ if (pr->adapter_path)
+ g_free(pr->adapter_path);
+ if (pr->msg)
+ dbus_message_unref(pr->msg);
+ if (pr->conn)
+ dbus_connection_unref(pr->conn);
+}
+
+static inline DBusMessage *does_not_exist(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists",
+ "No such connection");
+}
+
+static inline DBusMessage *already_exists(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists",
+ "Connection already exists");
+}
+
+static inline DBusMessage *not_supported(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotSupported",
+ "Not supported");
+}
+
+static inline DBusMessage *connection_is_busy(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Connection is Busy");
+}
+
+static inline DBusMessage *adapter_not_available(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Adapter not available");
+}
+
+static void create_path(DBusConnection *conn, DBusMessage *msg,
+ const char *path, const char *sname)
+{
+ /* emit signal when it is a new path */
+ if (sname) {
+ g_dbus_emit_signal(conn, NETWORK_PATH,
+ NETWORK_MANAGER_INTERFACE,
+ sname, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *list_paths(DBusConnection *conn, DBusMessage *msg,
+ GSList *list)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ for (; list; list = list->next) {
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING,
+ &list->data);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return reply;
+}
+
+static const char *last_connection_used(DBusConnection *conn)
+{
+ const char *path = NULL;
+ GSList *l;
+ int i;
+
+ for (i = g_slist_length (connection_paths) -1; i > -1; i--) {
+ path = g_slist_nth_data (connection_paths, i);
+ if (connection_is_connected(path))
+ break;
+ }
+
+ /* No connection connected fallback to last connection */
+ if (i == -1) {
+ l = g_slist_last(connection_paths);
+ path = l->data;
+ }
+
+ return path;
+}
+
+static DBusMessage *remove_path(DBusConnection *conn,
+ DBusMessage *msg, GSList **list,
+ const char *sname)
+{
+ const char *path;
+ GSList *l;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ l = g_slist_find_custom(*list, path, (GCompareFunc) strcmp);
+ if (!l)
+ return does_not_exist(msg);
+
+ /* Remove references from the storage */
+ if (*list == connection_paths) {
+ if (connection_has_pending(path))
+ return connection_is_busy(msg);
+
+ connection_remove_stored(path);
+ /* Reset default connection */
+ if (l == g_slist_nth(*list, default_index)) {
+ const char *dpath;
+
+ dpath = last_connection_used(conn);
+ connection_store(dpath, TRUE);
+ }
+ }
+
+ g_free(l->data);
+ *list = g_slist_remove(*list, l->data);
+
+ g_dbus_emit_signal(conn, NETWORK_PATH,
+ NETWORK_MANAGER_INTERFACE,
+ sname, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ g_dbus_unregister_interface(conn, path, NETWORK_CONNECTION_INTERFACE);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static void records_cb(sdp_list_t *recs, int err, gpointer data)
+{
+ struct pending_reply *pr = data;
+ int len;
+ sdp_data_t *d;
+ sdp_record_t *rec = NULL;
+ char name[MAX_NAME_SIZE], *desc = NULL;
+
+ if (err < 0) {
+ error_connection_attempt_failed(pr->conn, pr->msg, -err);
+ goto fail;
+ }
+
+ if (!recs || !recs->data) {
+ error_not_supported(pr->conn, pr->msg);
+ error("Invalid PAN service record");
+ goto fail;
+ }
+
+ rec = recs->data;
+
+ /* Concat remote name and service name */
+ memset(name, 0, MAX_NAME_SIZE);
+ if (read_remote_name(&pr->src, &pr->dst, name, MAX_NAME_SIZE) < 0)
+ len = 0;
+ else
+ len = strlen(name);
+
+ d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
+ if (d) {
+ snprintf(name + len, MAX_NAME_SIZE - len,
+ len ? " (%.*s)" : "%.*s", d->unitSize, d->val.str);
+ }
+
+ /* Extract service description from record */
+ d = sdp_data_get(rec, SDP_ATTR_SVCDESC_PRIMARY);
+ if (d) {
+ desc = g_new0(char, d->unitSize);
+ snprintf(desc, d->unitSize, "%.*s",
+ d->unitSize, d->val.str);
+ }
+
+ sdp_list_free(recs, (sdp_free_func_t) sdp_record_free);
+
+ if (connection_register(pr->path, &pr->src, &pr->dst, pr->id, name,
+ desc) < 0) {
+ error_failed(pr->conn, pr->msg, "D-Bus path registration failed");
+ goto fail;
+ }
+
+ connection_store(pr->path, FALSE);
+ connection_paths = g_slist_append(connection_paths, g_strdup(pr->path));
+
+ create_path(pr->conn, pr->msg, pr->path, "ConnectionCreated");
+
+fail:
+ g_free(desc);
+ pending_reply_free(pr);
+}
+
+static DBusMessage *list_servers(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return list_paths(conn, msg, server_paths);
+}
+
+static DBusMessage *find_server(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *pattern;
+ const char *path;
+ GSList *list;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ for (list = server_paths; list; list = list->next) {
+ path = (const char *) list->data;
+ if (server_find_data(path, pattern) == 0)
+ break;
+ }
+
+ if (list == NULL)
+ return does_not_exist(msg);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *list_connections(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return list_paths(conn, msg, connection_paths);
+}
+
+static GSList *find_connection_pattern(DBusConnection *conn,
+ const char *pattern)
+{
+ const char *path;
+ GSList *list;
+
+ if (pattern == NULL)
+ return NULL;
+
+ for (list = connection_paths; list; list = list->next) {
+ path = (const char *) list->data;
+ if (connection_find_data(path, pattern) == 0)
+ break;
+ }
+
+ return list;
+}
+
+static DBusMessage *find_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *pattern;
+ const char *path;
+ GSList *list;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ list = find_connection_pattern(conn, pattern);
+ if (list == NULL)
+ return does_not_exist(msg);
+
+ path = list->data;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *create_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct pending_reply *pr;
+ const char *addr;
+ const char *str;
+ bdaddr_t src;
+ uint16_t id;
+ int dev_id, err;
+ char key[32];
+ GSList *l;
+ uuid_t uuid;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ id = bnep_service_id(str);
+ if (id != BNEP_SVC_GN && id != BNEP_SVC_NAP && id != BNEP_SVC_PANU)
+ return not_supported(msg);
+
+ snprintf(key, 32, "%s#%s", addr, bnep_name(id));
+
+ /* Checks if the connection was already been made */
+ for (l = connection_paths; l; l = l->next) {
+ if (connection_find_data(l->data, key) == 0)
+ return already_exists(msg);
+ }
+
+ bacpy(&src, BDADDR_ANY);
+ dev_id = hci_get_route(&src);
+ if (dev_id < 0 || hci_devba(dev_id, &src) < 0)
+ return adapter_not_available(msg);
+
+ pr = g_new0(struct pending_reply, 1);
+
+ /* FIXME just to maintain compatibility */
+ pr->adapter_path = g_strdup_printf("/org/bluez/hci%d", dev_id);
+ if (!pr->adapter_path) {
+ pending_reply_free (pr);
+ return adapter_not_available(msg);
+ }
+
+ pr->conn = dbus_connection_ref(conn);
+ pr->msg = dbus_message_ref(msg);
+ bacpy(&pr->src, &src);
+ str2ba(addr, &pr->dst);
+ pr->addr = g_strdup(addr);
+ pr->id = id;
+ pr->path = g_new0(char, MAX_PATH_LENGTH);
+ snprintf(pr->path, MAX_PATH_LENGTH,
+ NETWORK_PATH "/connection%d", net_uid++);
+
+ sdp_uuid16_create(&uuid, pr->id);
+ err = bt_search_service(&pr->src, &pr->dst, &uuid, records_cb, pr,
+ NULL);
+ if (err < 0) {
+ pending_reply_free(pr);
+ return not_supported(msg);
+ }
+
+ return NULL;
+}
+
+static DBusMessage *remove_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return remove_path(conn, msg, &connection_paths, "ConnectionRemoved");
+}
+
+static DBusMessage *last_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+
+ if (connection_paths == NULL ||
+ g_slist_length(connection_paths) == 0)
+ return does_not_exist(msg);
+
+ path = last_connection_used(conn);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *default_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+
+ if (connection_paths == NULL ||
+ g_slist_length (connection_paths) == 0)
+ return does_not_exist(msg);
+
+ path = g_slist_nth_data (connection_paths, default_index);
+
+ if (path == NULL) {
+ path = last_connection_used(conn);
+ connection_store(path, TRUE);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *change_default_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+ const char *pattern;
+ GSList *list;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ if (connection_paths == NULL ||
+ g_slist_length(connection_paths) == 0)
+ return does_not_exist(msg);
+
+ list = g_slist_find_custom(connection_paths, pattern,
+ (GCompareFunc) strcmp);
+
+ /* Find object path via pattern */
+ if (list == NULL) {
+ list = find_connection_pattern(conn, pattern);
+ if (list == NULL)
+ return does_not_exist(msg);
+
+ path = list->data;
+ } else
+ path = list->data;
+
+ default_index = g_slist_position(connection_paths, list);
+ connection_store(path, TRUE);
+
+ g_dbus_emit_signal(connection, NETWORK_PATH,
+ NETWORK_MANAGER_INTERFACE,
+ "DefaultConnectionChanged",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+}
+
+static void manager_unregister(void *data)
+{
+ info("Unregistered manager path");
+
+ if (server_paths) {
+ g_slist_foreach(server_paths, (GFunc) g_free, NULL);
+ g_slist_free(server_paths);
+ server_paths = NULL;
+ }
+
+ if (connection_paths) {
+ g_slist_foreach(connection_paths, (GFunc) g_free, NULL);
+ g_slist_free(connection_paths);
+ connection_paths = NULL;
+ }
+
+ bnep_kill_all_connections();
+}
+
+static void parse_stored_connection(char *key, char *value, void *data)
+{
+ bdaddr_t dst, *src = data;
+ char path[MAX_PATH_LENGTH];
+ char addr[18];
+ const char *ptr;
+ char *name;
+ int len, id;
+
+ /* Format: XX:XX:XX:XX:XX:XX#{NAP, GN} name:description */
+
+ /* Parsing the key: address#role */
+ ptr = strchr(key, '#');
+
+ /* Empty address or invalid len */
+ if (!ptr || ((ptr - key) != 17))
+ return;
+
+ memset(addr, 0, 18);
+ strncpy(addr, key, 17);
+ str2ba(addr, &dst);
+
+ /* Empty role */
+ if (++ptr == NULL)
+ return;
+
+ if (strcasecmp("nap", ptr) == 0)
+ id = BNEP_SVC_NAP;
+ else if (strcasecmp("gn", ptr) == 0)
+ id = BNEP_SVC_GN;
+ else if (strcasecmp("panu", ptr) == 0)
+ id = BNEP_SVC_PANU;
+ else
+ return;
+
+ snprintf(path, MAX_PATH_LENGTH,
+ NETWORK_PATH "/connection%d", net_uid++);
+
+ /* Parsing the value: name and description */
+ ptr = strchr(value, ':');
+
+ /* Empty name */
+ if (!ptr)
+ return;
+
+ len = ptr-value;
+ name = g_malloc0(len + 1);
+ strncpy(name, value, len);
+
+ /* Empty description */
+ if (++ptr == NULL) {
+ g_free(name);
+ return;
+ }
+
+ if (connection_register(path, src, &dst, id, name, ptr) == 0) {
+ char *rpath = g_strdup(path);
+ connection_paths = g_slist_append(connection_paths, rpath);
+ }
+
+ g_free(name);
+}
+
+static void register_connections_stored(const char *adapter)
+{
+ char filename[PATH_MAX + 1];
+ char *pattern;
+ struct stat st;
+ GSList *list;
+ bdaddr_t src;
+ bdaddr_t default_src;
+ int dev_id;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter, "network");
+
+ str2ba(adapter, &src);
+
+ if (stat(filename, &st) < 0)
+ return;
+
+ if (!(st.st_mode & __S_IFREG))
+ return;
+
+ textfile_foreach(filename, parse_stored_connection, &src);
+
+ /* Check default connection for current default adapter */
+ bacpy(&default_src, BDADDR_ANY);
+ dev_id = hci_get_route(&default_src);
+ if (dev_id < 0 || hci_devba(dev_id, &default_src) < 0)
+ return;
+
+ if (bacmp(&default_src, &src) != 0)
+ return;
+
+ pattern = textfile_get(filename, "default");
+ if (!pattern)
+ return;
+
+ list = find_connection_pattern(connection, pattern);
+ if (!list)
+ return;
+ default_index = g_slist_position(connection_paths, list);
+}
+
+static void register_server(uint16_t id)
+{
+ char path[MAX_PATH_LENGTH];
+ bdaddr_t src;
+ int dev_id;
+
+ if (!conf->server_enabled)
+ return;
+
+ snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH "/%s", bnep_name(id));
+
+ if (g_slist_find_custom(server_paths, path,
+ (GCompareFunc) strcmp))
+ return;
+
+ bacpy(&src, BDADDR_ANY);
+ dev_id = hci_get_route(&src);
+ if (dev_id < 0 || hci_devba(dev_id, &src))
+ return;
+
+ if (server_register(path, &src, id) < 0)
+ return;
+
+ server_store(path);
+
+ server_paths = g_slist_append(server_paths, g_strdup(path));
+}
+
+static void register_servers_stored(const char *adapter, const char *profile)
+{
+ char filename[PATH_MAX + 1];
+ char path[MAX_PATH_LENGTH];
+ uint16_t id;
+ struct stat s;
+ bdaddr_t src;
+
+ if (strcmp(profile, "nap") == 0)
+ id = BNEP_SVC_NAP;
+ else if (strcmp(profile, "gn") == 0)
+ id = BNEP_SVC_GN;
+ else
+ id = BNEP_SVC_PANU;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter, profile);
+
+ str2ba(adapter, &src);
+
+ if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
+ snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH "/%s", profile);
+ if (server_register_from_file(path, &src, id, filename) == 0) {
+ server_paths = g_slist_append(server_paths,
+ g_strdup(path));
+ }
+ }
+}
+
+static void register_stored(void)
+{
+ char dirname[PATH_MAX + 1];
+ struct dirent *de;
+ DIR *dir;
+
+ snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
+
+ dir = opendir(dirname);
+ if (!dir)
+ return;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (!isdigit(de->d_name[0]))
+ continue;
+
+ /* Connection objects */
+ if (conf->connection_enabled)
+ register_connections_stored(de->d_name);
+
+ /* Server objects */
+ if (conf->server_enabled) {
+ /* NAP objects */
+ register_servers_stored(de->d_name, "nap");
+
+ /* GN objects */
+ register_servers_stored(de->d_name, "gn");
+
+ /* PANU objects */
+ register_servers_stored(de->d_name, "panu");
+ }
+ }
+
+ closedir(dir);
+}
+
+static GDBusMethodTable connection_methods[] = {
+ { "ListConnections", "", "as", list_connections },
+ { "FindConnection", "s", "s", find_connection },
+ { "CreateConnection", "ss", "s", create_connection,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "RemoveConnection", "s", "", remove_connection },
+ { "LastConnection", "", "s", last_connection },
+ { "DefaultConnection", "", "s", default_connection },
+ { "ChangeDefaultConnection", "s", "s", change_default_connection },
+ { }
+};
+
+static GDBusSignalTable connection_signals[] = {
+ { "ConnectionCreated", "s" },
+ { "ConnectionRemoved", "s" },
+ { "DefaultConnectionChanged", "s" },
+ { }
+};
+
+static GDBusMethodTable server_methods[] = {
+ { "ListServers", "", "as", list_servers },
+ { "FindServer", "s", "s", find_server },
+ { }
+};
+
+static GDBusMethodTable manager_methods[] = {
+ { "ListServers", "", "as", list_servers },
+ { "FindServer", "s", "s", find_server },
+ { "ListConnections", "", "as", list_connections },
+ { "FindConnection", "s", "s", find_connection },
+ { "CreateConnection", "ss", "s", create_connection,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "RemoveConnection", "s", "", remove_connection },
+ { "LastConnection", "", "s", last_connection },
+ { "DefaultConnection", "", "s", default_connection },
+ { "ChangeDefaultConnection", "s", "s", change_default_connection },
+ { }
+};
+
+int network_manager_init(DBusConnection *conn, struct network_conf *service_conf)
+{
+ GDBusMethodTable *methods = NULL;
+ GDBusSignalTable *signals = NULL;
+
+ conf = service_conf;
+
+ if (conf->server_enabled && conf->connection_enabled) {
+ methods = manager_methods;
+ signals = connection_signals;
+ } else if (conf->connection_enabled) {
+ methods = connection_methods;
+ signals = connection_signals;
+ } else if (conf->server_enabled)
+ methods = server_methods;
+ else {
+ error ("All interfaces were disabled");
+ return -1;
+ }
+
+ if (bnep_init(conf->panu_script, conf->gn_script, conf->nap_script)) {
+ error("Can't init bnep module");
+ return -1;
+ }
+
+ /*
+ * There is one socket to handle the incomming connections. NAP,
+ * GN and PANU servers share the same PSM. The initial BNEP message
+ * (setup connection request) contains the destination service
+ * field that defines which service the source is connecting to.
+ */
+ if (conf->server_enabled) {
+ 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)
+ return -1;
+ }
+
+ if (conf->connection_enabled) {
+ if (connection_init(conn, conf->iface_prefix) < 0)
+ return -1;
+ }
+
+ if (g_dbus_register_interface(conn, NETWORK_PATH,
+ NETWORK_MANAGER_INTERFACE,
+ methods, signals, NULL,
+ NULL, manager_unregister) == FALSE) {
+ error("Failed to register %s interface to %s",
+ NETWORK_MANAGER_INTERFACE, NETWORK_PATH);
+ return -1;
+ }
+
+ connection = dbus_connection_ref(conn);
+
+ info("Registered manager path:%s", NETWORK_PATH);
+
+ register_stored();
+
+ /* Register PANU, GN and NAP servers if they don't exist */
+ register_server(BNEP_SVC_PANU);
+ register_server(BNEP_SVC_GN);
+ register_server(BNEP_SVC_NAP);
+
+ return 0;
+}
+
+void network_manager_exit(void)
+{
+ if (conf->server_enabled)
+ server_exit();
+
+ if (conf->connection_enabled)
+ connection_exit();
+
+ g_dbus_unregister_interface(connection, NETWORK_PATH,
+ NETWORK_MANAGER_INTERFACE);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+
+ bnep_cleanup();
+ bridge_cleanup();
+}
+
+static inline int create_filename(char *buf, size_t size,
+ bdaddr_t *bdaddr, const char *name)
+{
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+
+ return create_name(buf, size, STORAGEDIR, addr, name);
+}
diff --git a/utils/network/manager.h b/utils/network/manager.h
new file mode 100644
index 00000000..9b16c2a3
--- /dev/null
+++ b/utils/network/manager.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "connection.h"
+#include "server.h"
+
+#define MAX_PATH_LENGTH 64 /* D-Bus path */
+#define NETWORK_PATH "/org/bluez/network"
+
+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;
+};
+
+int network_manager_init(DBusConnection *conn, struct network_conf *service_conf);
+void network_manager_exit(void);
diff --git a/utils/network/network-api.txt b/utils/network/network-api.txt
new file mode 100644
index 00000000..2d46abfd
--- /dev/null
+++ b/utils/network/network-api.txt
@@ -0,0 +1,199 @@
+Bluetooth network service API description
+*****************************************
+
+Copyright (C) 2006-2007 Marcel Holtmann <marcel@holtmann.org>
+
+
+Network Manager hierarchy
+=========================
+
+Interface org.bluez.network.Manager
+Object path /org/bluez/network
+
+Methods array{string} ListServers()
+
+ Returns an array of available network devices paths.
+ Currently only NAP and GN are supported.
+
+ string FindServer(string pattern)
+
+ Returns server path.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+ string CreateConnection(string address, string uuid)
+
+ Creates a network connection object(NAP or GN).
+
+ Possible errors: org.bluez.Error.AlreadyExists
+ org.bluez.Error.NotSupported
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.Failed
+
+ void RemoveConnection(string path)
+
+ Removes a network connection object for a given path.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+ array{string} ListConnections()
+
+ Returns an array of available network connections paths.
+
+ string FindConnection(string pattern)
+
+ Returns connection path.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+ org.bluez.Error.Failed
+
+ string LastConnection()
+
+ Returns last connected connection path, if none is connected
+ fallback to last created connection.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+ string DefaultConnection()
+
+ Returns default connection path.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+ string ChangeDefaultConnection(string pattern)
+
+ Changes default connection path.
+
+ Possible errors: org.bluez.Error.DoesNotExist
+
+Signals void ConnectionCreated(string path)
+
+ void ConnectionRemoved(string path)
+
+ void DefaultConnectionChanged(string path)
+
+
+Network Server hierarchy (experimental)
+=======================================
+
+Interface org.bluez.network.Server
+Object path /org/bluez/network/{gn, nap, panu}
+
+Methods string GetUUID()
+
+ Returns the UUID-128 string representation of
+ the server.
+
+ void Enable()
+
+ Enable server and updates service record.
+
+ Possible errors: org.bluez.Error.AlreadyExists
+ org.bluez.Error.Failed
+
+ void Disable()
+
+ Disable server and remove service record.
+
+ Possible errors: org.bluez.Error.Failed
+
+ bool IsEnabled()
+
+ Returns the server status.
+
+ void SetName(string name)
+
+ Sets the name attribute.
+
+ string GetName()
+
+ Returns the service name.
+
+ void SetAddressRange(string start, string end)
+
+ TBD
+
+ void SetRouting(string interface)
+
+ TBD
+
+ dict GetInfo()
+
+ Returns the server properties.
+
+Signals void Enabled()
+
+ void Disabled()
+
+
+Network Connection hierarchy (experimental)
+===========================================
+
+Interface org.bluez.network.Connection
+Object path /org/bluez/network/connection*
+
+Methods string GetAdapter()
+
+ Returns the Bluetooth address of the adapter.
+
+ string GetAddress()
+
+ Returns the Bluetooth address of the ending point.
+
+ string GetUUID()
+
+ Returns the uuid 128 string representation of
+ the connected service.
+
+ string GetName()
+
+ Returns the string representation of connected host.
+
+ Possible errors: org.bluez.Error.Failed
+
+ string GetDescription()
+
+ Returns the string description of connected host.
+
+ Possible errors: org.bluez.Error.Failed
+
+ string GetInterface()
+
+ Returns the string network interface.
+
+ Possible errors: org.bluez.Error.Failed
+
+ string Connect()
+
+ Connects to host and return the network interface
+ created.
+
+ Possible errors: org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.Failed
+
+ void CancelConnect()
+
+ Abort connection attempt in case of errors or
+ timeouts in the client.
+
+ Possible errors: org.bluez.Error.Failed
+
+ void Disconnect()
+
+ Disconnects to host.
+
+ Possible errors: org.bluez.Error.Failed
+
+ bool IsConnected()
+
+ Returns the connection status.
+
+ dict GetInfo()
+
+ Returns the connection properties.
+
+Signals void Connected()
+
+ void Disconnected()
diff --git a/utils/network/network.conf b/utils/network/network.conf
new file mode 100644
index 00000000..8677bd7b
--- /dev/null
+++ b/utils/network/network.conf
@@ -0,0 +1,37 @@
+# Configuration file for the network service
+
+# This section contains options which are not specific to any
+# particular interface
+[General]
+
+# If we want to disable support for specific services
+# Defaults to supporting all implemented services
+#Disable=Connection,Server
+
+# 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/utils/network/server.c b/utils/network/server.c
new file mode 100644
index 00000000..e94964ae
--- /dev/null
+++ b/utils/network/server.c
@@ -0,0 +1,1097 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <net/if.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/bnep.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <netinet/in.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "../hcid/dbus-common.h"
+
+#include "logging.h"
+#include "error.h"
+#include "textfile.h"
+#include "dbus-service.h"
+#include "sdpd.h"
+#include "glib-helper.h"
+
+#define NETWORK_SERVER_INTERFACE "org.bluez.network.Server"
+#define SETUP_TIMEOUT 1000
+#define MAX_SETUP_ATTEMPTS 3
+
+#include "bridge.h"
+#include "common.h"
+#include "manager.h"
+
+/* Pending Authorization */
+struct setup_session {
+ char *address; /* Remote Bluetooth Address */
+ uint16_t dst_role; /* Destination role */
+ uint16_t src_role; /* Source role */
+ int nsk; /* L2CAP socket */
+ guint watch; /* BNEP socket watch */
+};
+
+struct timeout {
+ guint id; /* Timeout id */
+ guint watch; /* BNEP socket watch */
+};
+
+/* Main server structure */
+struct network_server {
+ bdaddr_t src; /* Bluetooth Local Address */
+ char *iface; /* Routing interface */
+ char *name; /* Server service name */
+ char *range; /* IP Address range */
+ char *path; /* D-Bus path */
+ gboolean enable; /* Enable flag */
+ uint32_t record_id; /* Service record id */
+ uint16_t id; /* Service class identifier */
+ GSList *clients; /* Active connections */
+};
+
+static GIOChannel *bnep_io = NULL;
+static DBusConnection *connection = NULL;
+static struct setup_session *setup = NULL;
+static GSList *servers = NULL;
+static const char *prefix = NULL;
+static gboolean security = TRUE;
+
+gint find_server(gconstpointer a, gconstpointer b)
+{
+ const struct network_server *ns = a;
+ const char *path = b;
+
+ return strcmp(ns->path, path);
+}
+
+static struct setup_session *setup_session_new(gchar *address,
+ uint16_t dst_role, uint16_t src_role, int nsk, guint watch)
+{
+ struct setup_session *setup;
+
+ setup = g_new0(struct setup_session, 1);
+ setup->address = g_strdup(address);
+ setup->dst_role = dst_role;
+ setup->src_role = src_role;
+ setup->nsk = nsk;
+ setup->watch = watch;
+
+ return setup;
+}
+
+static void setup_session_free(struct setup_session *setup)
+{
+ g_source_remove(setup->watch);
+ g_free(setup->address);
+ g_free(setup);
+}
+
+static struct network_server *server_find(bdaddr_t *src, uint16_t role)
+{
+ struct network_server *ns;
+ GSList *l;
+
+ for (l = servers; l; l = l->next) {
+ ns = l->data;
+ if (bacmp(&ns->src, src) != 0)
+ continue;
+ if (ns->id == role)
+ return ns;
+ }
+
+ return NULL;
+}
+
+static int store_property(bdaddr_t *src, uint16_t id,
+ const char *key, const char *value)
+{
+ char filename[PATH_MAX + 1];
+ char addr[18];
+
+ ba2str(src, addr);
+ if (id == BNEP_SVC_NAP)
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
+ else if (id == BNEP_SVC_GN)
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
+ else if (id == BNEP_SVC_PANU)
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "panu");
+
+ return textfile_put(filename, key, value);
+}
+
+static void add_lang_attr(sdp_record_t *r)
+{
+ sdp_lang_attr_t base_lang;
+ sdp_list_t *langs = 0;
+
+ /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
+ base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
+ base_lang.encoding = 106;
+ base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
+ langs = sdp_list_append(0, &base_lang);
+ sdp_set_lang_attr(r, langs);
+ sdp_list_free(langs, 0);
+}
+
+static sdp_record_t *server_record_new(const char *name, uint16_t id)
+{
+ sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
+ uuid_t root_uuid, pan, l2cap, bnep;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *proto[2];
+ sdp_data_t *v, *p;
+ uint16_t psm = BNEP_PSM, version = 0x0100;
+ 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";
+ sdp_record_t *record;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ record->attrlist = NULL;
+ record->pattern = NULL;
+
+ switch (id) {
+ case BNEP_SVC_NAP:
+ sdp_uuid16_create(&pan, NAP_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &pan);
+ sdp_set_service_classes(record, svclass);
+
+ sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_set_info_attr(record, name, NULL, desc);
+
+ sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE,
+ SDP_UINT16, &net_access_type);
+ sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE,
+ SDP_UINT32, &max_net_access_rate);
+ break;
+ case BNEP_SVC_GN:
+ sdp_uuid16_create(&pan, GN_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &pan);
+ sdp_set_service_classes(record, svclass);
+
+ sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_set_info_attr(record, name, NULL, desc);
+ break;
+ case BNEP_SVC_PANU:
+ sdp_uuid16_create(&pan, PANU_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &pan);
+ sdp_set_service_classes(record, svclass);
+
+ sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_set_info_attr(record, name, NULL, desc);
+ break;
+ default:
+ 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(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(NULL, &l2cap);
+ p = sdp_data_alloc(SDP_UINT16, &psm);
+ proto[0] = sdp_list_append(proto[0], p);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&bnep, BNEP_UUID);
+ proto[1] = sdp_list_append(NULL, &bnep);
+ v = sdp_data_alloc(SDP_UINT16, &version);
+ proto[1] = sdp_list_append(proto[1], v);
+
+ /* Supported protocols */
+ {
+ uint16_t ptype[] = {
+ 0x0800, /* IPv4 */
+ 0x0806, /* ARP */
+ };
+ sdp_data_t *head, *pseq;
+ int p;
+
+ for (p = 0, head = NULL; p < 2; p++) {
+ sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
+ if (head)
+ sdp_seq_append(head, data);
+ else
+ head = data;
+ }
+ pseq = sdp_data_alloc(SDP_SEQ16, head);
+ proto[1] = sdp_list_append(proto[1], pseq);
+ }
+
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ add_lang_attr(record);
+
+ sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC,
+ SDP_UINT16, &security_desc);
+
+ sdp_data_free(p);
+ sdp_data_free(v);
+ sdp_list_free(apseq, NULL);
+ sdp_list_free(root, NULL);
+ sdp_list_free(aproto, NULL);
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(proto[1], NULL);
+ sdp_list_free(svclass, NULL);
+ sdp_list_free(pfseq, NULL);
+
+ return record;
+}
+
+static ssize_t send_bnep_ctrl_rsp(int sk, uint16_t val)
+{
+ struct bnep_control_rsp rsp;
+
+ rsp.type = BNEP_CONTROL;
+ rsp.ctrl = BNEP_SETUP_CONN_RSP;
+ rsp.resp = htons(val);
+
+ return send(sk, &rsp, sizeof(rsp), 0);
+}
+
+static int server_connadd(struct network_server *ns, int nsk,
+ const gchar *address, uint16_t dst_role)
+{
+ char devname[16];
+ const char *bridge;
+ int err;
+
+ /* Server can be disabled in the meantime */
+ if (ns->enable == FALSE)
+ return -EPERM;
+
+ memset(devname, 0, 16);
+ strncpy(devname, prefix, strlen(prefix));
+
+ err = bnep_connadd(nsk, dst_role, devname);
+ if (err < 0)
+ return err;
+
+ 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;
+ }
+
+ bnep_if_up(devname, 0);
+ } else
+ bnep_if_up(devname, ns->id);
+
+ ns->clients = g_slist_append(ns->clients, g_strdup(address));
+
+ return 0;
+}
+
+static void req_auth_cb(DBusError *derr, void *user_data)
+{
+ struct network_server *ns = user_data;
+ uint16_t val;
+
+ if (!setup) {
+ info("Authorization cancelled: Client exited");
+ return;
+ }
+
+ if (derr) {
+ error("Access denied: %s", derr->message);
+ if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {
+ bdaddr_t dst;
+ str2ba(setup->address, &dst);
+ service_cancel_auth(&ns->src, &dst);
+ }
+ val = BNEP_CONN_NOT_ALLOWED;
+ goto done;
+ }
+
+ if (server_connadd(ns, setup->nsk,
+ setup->address, setup->dst_role) < 0)
+ val = BNEP_CONN_NOT_ALLOWED;
+ else
+ val = BNEP_SUCCESS;
+
+done:
+ send_bnep_ctrl_rsp(setup->nsk, val);
+ setup_session_free(setup);
+ setup = NULL;
+}
+
+static int authorize_connection(struct network_server *ns, const char *address)
+{
+ const char *uuid;
+ bdaddr_t dst;
+ int ret_val;
+
+ uuid = bnep_uuid(ns->id);
+ str2ba(address, &dst);
+
+ ret_val = service_req_auth(&ns->src, &dst, uuid, req_auth_cb, ns);
+
+ return ret_val;
+}
+
+static uint16_t inline bnep_setup_chk(uint16_t dst_role, uint16_t src_role)
+{
+ /* Allowed PAN Profile scenarios */
+ switch (dst_role) {
+ case BNEP_SVC_NAP:
+ case BNEP_SVC_GN:
+ if (src_role == BNEP_SVC_PANU)
+ return 0;
+ 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)
+ return 0;
+
+ return BNEP_CONN_INVALID_SRC;
+ }
+
+ return BNEP_CONN_INVALID_DST;
+}
+
+static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req,
+ uint16_t *dst_role, uint16_t *src_role)
+{
+ uint8_t *dest, *source;
+
+ dest = req->service;
+ source = req->service + req->uuid_size;
+
+ switch (req->uuid_size) {
+ case 2: /* UUID16 */
+ *dst_role = ntohs(bt_get_unaligned((uint16_t *) dest));
+ *src_role = ntohs(bt_get_unaligned((uint16_t *) source));
+ break;
+ case 4: /* UUID32 */
+ case 16: /* UUID128 */
+ *dst_role = ntohl(bt_get_unaligned((uint32_t *) dest));
+ *src_role = ntohl(bt_get_unaligned((uint32_t *) source));
+ break;
+ default:
+ return BNEP_CONN_INVALID_SVC;
+ }
+
+ return 0;
+}
+
+static gboolean bnep_setup(GIOChannel *chan,
+ GIOCondition cond, gpointer user_data)
+{
+ struct timeout *to = user_data;
+ struct network_server *ns;
+ uint8_t packet[BNEP_MTU];
+ struct bnep_setup_conn_req *req = (void *) packet;
+ struct sockaddr_l2 sa;
+ socklen_t size;
+ char address[18];
+ uint16_t rsp, src_role, dst_role;
+ int n, sk;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_ERR | G_IO_HUP)) {
+ error("Hangup or error on BNEP socket");
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
+ n = read(sk, packet, sizeof(packet));
+ if (n < 0) {
+ error("read(): %s(%d)", strerror(errno), errno);
+ return FALSE;
+ }
+
+ if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
+ return FALSE;
+
+ rsp = bnep_setup_decode(req, &dst_role, &src_role);
+ if (rsp)
+ goto reply;
+
+ rsp = bnep_setup_chk(dst_role, src_role);
+ if (rsp)
+ goto reply;
+
+ size = sizeof(sa);
+ if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ ba2str(&sa.l2_bdaddr, address);
+ ns = server_find(&sa.l2_bdaddr, dst_role);
+ if (!ns || ns->enable == FALSE) {
+ error("Server unavailable: %s (0x%x)", address, dst_role);
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ ba2str(&sa.l2_bdaddr, address);
+
+ if (setup) {
+ error("Connection rejected: Pending authorization");
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ setup = setup_session_new(address, dst_role, src_role, sk, to->watch);
+
+ /* Wait authorization before reply success */
+ if (authorize_connection(ns, address) < 0) {
+ setup_session_free(setup);
+ setup = NULL;
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto reply;
+ }
+
+ g_source_remove(to->id);
+ to->id = 0;
+
+ return TRUE;
+
+reply:
+ send_bnep_ctrl_rsp(sk, rsp);
+
+ return FALSE;
+}
+
+static void setup_destroy(void *user_data)
+{
+ struct timeout *to = user_data;
+
+ if (to->id)
+ g_source_remove(to->id);
+
+ g_free(to);
+}
+
+static gboolean timeout_cb(void *user_data)
+{
+ struct timeout *to = user_data;
+
+ to->id = 0;
+ g_source_remove(to->watch);
+
+ return FALSE;
+}
+
+static void connect_event(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct timeout *to;
+
+ if (err < 0) {
+ error("accept(): %s(%d)", strerror(errno), errno);
+ return;
+ }
+
+ g_io_channel_set_close_on_unref(chan, TRUE);
+
+ /*
+ * BNEP_SETUP_CONNECTION_REQUEST_MSG shall be received and
+ * user shall authorize the incomming connection before
+ * the time expires.
+ */
+ to = g_malloc0(sizeof(struct timeout));
+ to->id = g_timeout_add(SETUP_TIMEOUT, timeout_cb, to);
+ to->watch = g_io_add_watch_full(chan, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ bnep_setup, to, setup_destroy);
+ g_io_channel_unref(chan);
+
+ return;
+}
+
+int server_init(DBusConnection *conn, const char *iface_prefix,
+ gboolean secure)
+{
+ int lm;
+
+ lm = secure ? L2CAP_LM_SECURE : 0;
+
+ security = secure;
+ connection = dbus_connection_ref(conn);
+ prefix = iface_prefix;
+
+ bnep_io = bt_l2cap_listen(BDADDR_ANY, BNEP_PSM, BNEP_MTU, lm,
+ connect_event, NULL);
+ if (!bnep_io)
+ return -1;
+ g_io_channel_set_close_on_unref(bnep_io, FALSE);
+
+ if (bridge_create(BNEP_SVC_GN) < 0)
+ error("Can't create GN bridge");
+
+ return 0;
+}
+
+void server_exit()
+{
+ if (bnep_io != NULL) {
+ g_io_channel_close(bnep_io);
+ g_io_channel_unref(bnep_io);
+ bnep_io = NULL;
+ }
+
+ if (bridge_remove(BNEP_SVC_GN) < 0)
+ error("Can't remove GN bridge");
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
+
+static uint32_t register_server_record(struct network_server *ns)
+{
+ sdp_record_t *record;
+
+ record = server_record_new(ns->name, ns->id);
+ if (!record) {
+ error("Unable to allocate new service record");
+ return 0;
+ }
+
+ if (add_record_to_server(&ns->src, record) < 0) {
+ error("Failed to register service record");
+ sdp_record_free(record);
+ return 0;
+ }
+
+ debug("register_server_record: got record id 0x%x", record->handle);
+
+ return record->handle;
+}
+
+static DBusMessage *get_uuid(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_server *ns = data;
+ DBusMessage *reply;
+ const char *uuid;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ uuid = bnep_uuid(ns->id);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static inline DBusMessage *failed(DBusMessage *msg, const char *description)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ description);
+}
+
+static inline DBusMessage *invalid_arguments(DBusMessage *msg,
+ const char *description)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ description);
+}
+
+static DBusMessage *enable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_server *ns = data;
+ DBusMessage *reply;
+
+ if (ns->enable)
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".AlreadyExist",
+ "Server already enabled");
+
+ if (bacmp(&ns->src, BDADDR_ANY) == 0) {
+ int dev_id;
+
+ dev_id = hci_get_route(&ns->src);
+ if ((dev_id < 0) || (hci_devba(dev_id, &ns->src) < 0))
+ return failed(msg, "Adapter not available");
+
+ /* Store the server info */
+ server_store(ns->path);
+ }
+
+ 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;
+
+ store_property(&ns->src, ns->id, "enabled", "1");
+
+ g_dbus_emit_signal(conn, ns->path, NETWORK_SERVER_INTERFACE,
+ "Enabled", DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static void kill_connection(void *data, void *udata)
+{
+ const char *address = data;
+ bdaddr_t dst;
+
+ str2ba(address, &dst);
+ bnep_kill_connection(&dst);
+}
+
+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->clients, (GFunc) kill_connection, NULL);
+
+ store_property(&ns->src, ns->id, "enabled", "0");
+
+ g_dbus_emit_signal(conn, ns->path, NETWORK_SERVER_INTERFACE,
+ "Disabled", DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *is_enabled(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct network_server *ns = data;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ns->enable,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *set_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_server *ns = data;
+ DBusMessage *reply;
+ const char *name;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ 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;
+ }
+
+ store_property(&ns->src, ns->id, "name", ns->name);
+
+ return reply;
+}
+
+static DBusMessage *get_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_server *ns = data;
+ char name[] = "";
+ const char *pname = (ns->name ? ns->name : name);
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &pname,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *set_address_range(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return NULL;
+}
+
+static DBusMessage *set_routing(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct network_server *ns = data;
+ const char *iface;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &iface,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ /* FIXME: Check if the interface is valid/UP */
+ if (!iface || (strlen(iface) == 0))
+ return invalid_arguments(msg, "Invalid interface");
+
+ if (ns->iface)
+ g_free(ns->iface);
+ ns->iface = g_strdup(iface);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *get_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct network_server *ns = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ const char *uuid;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dbus_message_iter_append_dict_entry(&dict, "name",
+ DBUS_TYPE_STRING, &ns->name);
+
+ uuid = bnep_uuid(ns->id);
+ dbus_message_iter_append_dict_entry(&dict, "uuid",
+ DBUS_TYPE_STRING, &uuid);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static void server_free(struct network_server *ns)
+{
+ if (!ns)
+ return;
+
+ /* FIXME: Missing release/free all bnepX interfaces */
+ 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);
+
+ if (ns->path)
+ g_free(ns->path);
+
+ if (ns->clients) {
+ g_slist_foreach(ns->clients, (GFunc) g_free, NULL);
+ g_slist_free(ns->clients);
+ }
+
+ g_free(ns);
+}
+
+static void server_unregister(void *data)
+{
+ struct network_server *ns = data;
+
+ info("Unregistered server path:%s", ns->path);
+
+ servers = g_slist_remove(servers, ns);
+ server_free(ns);
+}
+
+static GDBusMethodTable server_methods[] = {
+ { "GetUUID", "", "s", get_uuid },
+ { "Enable", "", "", enable },
+ { "Disable", "", "", disable },
+ { "IsEnabled", "", "b", is_enabled },
+ { "SetName", "s", "", set_name },
+ { "GetName", "", "s", get_name },
+ { "SetAddressRange", "ss", "", set_address_range },
+ { "SetRouting", "s", "", set_routing },
+ { "GetInfo", "", "a{sv}",get_info },
+ { }
+};
+
+static GDBusSignalTable server_signals[] = {
+ { "Enabled", "" },
+ { "Disabled", "" },
+ { }
+};
+
+int server_register(const char *path, bdaddr_t *src, uint16_t id)
+{
+ struct network_server *ns;
+
+ if (!path)
+ return -EINVAL;
+
+ ns = g_new0(struct network_server, 1);
+
+ if (!g_dbus_register_interface(connection, path,
+ NETWORK_SERVER_INTERFACE,
+ server_methods, server_signals, NULL,
+ ns, server_unregister)) {
+ error("D-Bus failed to register %s interface",
+ NETWORK_SERVER_INTERFACE);
+ server_free(ns);
+ return -1;
+ }
+
+ /* Setting a default name */
+ if (id == BNEP_SVC_NAP)
+ ns->name = g_strdup("BlueZ NAP service");
+ else if (id == BNEP_SVC_GN)
+ ns->name = g_strdup("BlueZ GN service");
+ else
+ ns->name = g_strdup("BlueZ PANU service");
+
+ ns->path = g_strdup(path);
+ ns->id = id;
+ bacpy(&ns->src, src);
+
+ servers = g_slist_append(servers, ns);
+
+ info("Registered server path:%s", path);
+
+ return 0;
+}
+
+int server_register_from_file(const char *path, const bdaddr_t *src,
+ uint16_t id, const char *filename)
+{
+ struct network_server *ns;
+ char *str;
+
+ if (!path)
+ return -EINVAL;
+
+ ns = g_new0(struct network_server, 1);
+
+ bacpy(&ns->src, src);
+ ns->path = g_strdup(path);
+ ns->id = id;
+ ns->name = textfile_get(filename, "name");
+ if (!ns->name) {
+ /* Name is mandatory */
+ server_free(ns);
+ return -1;
+ }
+
+ ns->range = textfile_get(filename, "address_range");
+ ns->iface = textfile_get(filename, "routing");
+
+ str = textfile_get(filename, "enabled");
+ if (str) {
+ if (strcmp("1", str) == 0) {
+ ns->record_id = register_server_record(ns);
+ ns->enable = TRUE;
+ }
+ g_free(str);
+ }
+
+ if (!g_dbus_register_interface(connection, path,
+ NETWORK_SERVER_INTERFACE,
+ server_methods, server_signals, NULL,
+ ns, server_unregister)) {
+ error("D-Bus failed to register %s interface",
+ NETWORK_SERVER_INTERFACE);
+ server_free(ns);
+ return -1;
+ }
+
+ servers = g_slist_append(servers, ns);
+
+ info("Registered server path:%s", path);
+
+ return 0;
+}
+
+int server_store(const char *path)
+{
+ struct network_server *ns;
+ char filename[PATH_MAX + 1];
+ char addr[18];
+ GSList *l;
+
+ l = g_slist_find_custom(servers, path, find_server);
+ if (!l) {
+ error("Unable to salve %s on storage", path);
+ return -ENOENT;
+ }
+
+ ns = l->data;
+ ba2str(&ns->src, addr);
+ if (ns->id == BNEP_SVC_NAP)
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
+ else if (ns->id == BNEP_SVC_GN)
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
+ else
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "panu");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ textfile_put(filename, "name", ns->name);
+
+ if (ns->iface)
+ textfile_put(filename, "routing", ns->iface);
+
+ if (ns->range)
+ textfile_put(filename, "range", ns->range);
+
+ textfile_put(filename, "enabled", ns->enable ? "1": "0");
+
+ return 0;
+}
+
+int server_find_data(const char *path, const char *pattern)
+{
+ struct network_server *ns;
+ const char *uuid;
+ GSList *l;
+
+ l = g_slist_find_custom(servers, path, find_server);
+ if (!l)
+ return -1;
+
+ ns = l->data;
+ if (ns->name && strcasecmp(pattern, ns->name) == 0)
+ return 0;
+
+ if (ns->iface && strcasecmp(pattern, ns->iface) == 0)
+ return 0;
+
+ uuid = bnep_name(ns->id);
+ if (uuid && strcasecmp(pattern, uuid) == 0)
+ return 0;
+
+ if (bnep_service_id(pattern) == ns->id)
+ return 0;
+
+ return -1;
+}
diff --git a/utils/network/server.h b/utils/network/server.h
new file mode 100644
index 00000000..6fb06b58
--- /dev/null
+++ b/utils/network/server.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 server_init(DBusConnection *conn, const char *iface_prefix,
+ gboolean secure);
+void server_exit();
+int server_register(const char *path, bdaddr_t *src, 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_find_data(const char *path, const char *pattern);
diff --git a/utils/network/test-network b/utils/network/test-network
new file mode 100755
index 00000000..f428c25f
--- /dev/null
+++ b/utils/network/test-network
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Manager')
+
+conn = manager.ActivateService('network')
+
+network = dbus.Interface(bus.get_object(conn, '/org/bluez/network'),
+ 'org.bluez.network.Manager')
+
+try:
+ nap = dbus.Interface(bus.get_object(conn, network.FindServer('nap')),
+ 'org.bluez.network.Server')
+except:
+ pass
+
+try:
+ gn = dbus.Interface(bus.get_object(conn, network.FindServer('gn')),
+ 'org.bluez.network.Server')
+except:
+ pass
+
+try:
+ panu = dbus.Interface(bus.get_object(conn, network.FindServer('panu')),
+ 'org.bluez.network.Server')
+except:
+ pass
+
+try:
+ client = dbus.Interface(bus.get_object(conn, network.LastConnection()),
+ 'org.bluez.network.Connection')
+except:
+ pass
diff --git a/utils/pand/Makefile.am b/utils/pand/Makefile.am
new file mode 100644
index 00000000..85d70542
--- /dev/null
+++ b/utils/pand/Makefile.am
@@ -0,0 +1,22 @@
+
+if PAND
+bin_PROGRAMS = pand
+
+pand_SOURCES = main.c pand.h bnep.c sdp.c
+
+pand_LDADD = @BLUEZ_LIBS@
+endif
+
+AM_CFLAGS = @BLUEZ_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common
+
+if PAND
+if MANPAGES
+man_MANS = pand.1
+endif
+endif
+
+EXTRA_DIST = pand.1
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/pand/Makefile.in b/utils/pand/Makefile.in
new file mode 100644
index 00000000..c95873b4
--- /dev/null
+++ b/utils/pand/Makefile.in
@@ -0,0 +1,540 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@PAND_TRUE@bin_PROGRAMS = pand$(EXEEXT)
+subdir = pand
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__pand_SOURCES_DIST = main.c pand.h bnep.c sdp.c
+@PAND_TRUE@am_pand_OBJECTS = main.$(OBJEXT) bnep.$(OBJEXT) \
+@PAND_TRUE@ sdp.$(OBJEXT)
+pand_OBJECTS = $(am_pand_OBJECTS)
+pand_DEPENDENCIES =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(pand_SOURCES)
+DIST_SOURCES = $(am__pand_SOURCES_DIST)
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@PAND_TRUE@pand_SOURCES = main.c pand.h bnep.c sdp.c
+@PAND_TRUE@pand_LDADD = @BLUEZ_LIBS@
+AM_CFLAGS = @BLUEZ_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
+@MANPAGES_TRUE@@PAND_TRUE@man_MANS = pand.1
+EXTRA_DIST = pand.1
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pand/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu pand/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+pand$(EXEEXT): $(pand_OBJECTS) $(pand_DEPENDENCIES)
+ @rm -f pand$(EXEEXT)
+ $(LINK) $(pand_OBJECTS) $(pand_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bnep.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdp.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(man1_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-man \
+ uninstall-man1
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/pand/bnep.c b/utils/pand/bnep.c
new file mode 100644
index 00000000..604ed552
--- /dev/null
+++ b/utils/pand/bnep.c
@@ -0,0 +1,311 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/bnep.h>
+
+#include <netinet/in.h>
+
+#include "pand.h"
+
+static int ctl;
+
+/* Compatibility with old ioctls */
+#define OLD_BNEPCONADD 1
+#define OLD_BNEPCONDEL 2
+#define OLD_BNEPGETCONLIST 3
+#define OLD_BNEPGETCONINFO 4
+
+static unsigned long bnepconnadd;
+static unsigned long bnepconndel;
+static unsigned long bnepgetconnlist;
+static unsigned long bnepgetconninfo;
+
+static struct {
+ char *str;
+ uint16_t uuid;
+} __svc[] = {
+ { "PANU", BNEP_SVC_PANU },
+ { "NAP", BNEP_SVC_NAP },
+ { "GN", BNEP_SVC_GN },
+ { NULL }
+};
+
+int bnep_str2svc(char *svc, uint16_t *uuid)
+{
+ int i;
+ for (i = 0; __svc[i].str; i++)
+ if (!strcasecmp(svc, __svc[i].str)) {
+ *uuid = __svc[i].uuid;
+ return 0;
+ }
+ return -1;
+}
+
+char *bnep_svc2str(uint16_t uuid)
+{
+ int i;
+ for (i = 0; __svc[i].str; i++)
+ if (__svc[i].uuid == uuid)
+ return __svc[i].str;
+ return NULL;
+}
+
+int bnep_init(void)
+{
+ ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
+ if (ctl < 0) {
+ perror("Failed to open control socket");
+ return 1;
+ }
+
+ /* Temporary ioctl compatibility hack */
+ {
+ struct bnep_connlist_req req;
+ struct bnep_conninfo ci[1];
+
+ req.cnum = 1;
+ req.ci = ci;
+
+ if (!ioctl(ctl, BNEPGETCONNLIST, &req)) {
+ /* New ioctls */
+ bnepconnadd = BNEPCONNADD;
+ bnepconndel = BNEPCONNDEL;
+ bnepgetconnlist = BNEPGETCONNLIST;
+ bnepgetconninfo = BNEPGETCONNINFO;
+ } else {
+ /* Old ioctls */
+ bnepconnadd = OLD_BNEPCONADD;
+ bnepconndel = OLD_BNEPCONDEL;
+ bnepgetconnlist = OLD_BNEPGETCONLIST;
+ bnepgetconninfo = OLD_BNEPGETCONINFO;
+ }
+ }
+
+ return 0;
+}
+
+int bnep_cleanup(void)
+{
+ close(ctl);
+ return 0;
+}
+
+int bnep_show_connections(void)
+{
+ struct bnep_connlist_req req;
+ struct bnep_conninfo ci[48];
+ int i;
+
+ req.cnum = 48;
+ req.ci = ci;
+ if (ioctl(ctl, bnepgetconnlist, &req)) {
+ perror("Failed to get connection list");
+ return -1;
+ }
+
+ for (i=0; i < req.cnum; i++) {
+ printf("%s %s %s\n", ci[i].device,
+ batostr((bdaddr_t *) ci[i].dst),
+ bnep_svc2str(ci[i].role));
+ }
+ return 0;
+}
+
+int bnep_kill_connection(uint8_t *dst)
+{
+ struct bnep_conndel_req req;
+
+ memcpy(req.dst, dst, ETH_ALEN);
+ req.flags = 0;
+ if (ioctl(ctl, bnepconndel, &req)) {
+ perror("Failed to kill connection");
+ return -1;
+ }
+ return 0;
+}
+
+int bnep_kill_all_connections(void)
+{
+ struct bnep_connlist_req req;
+ struct bnep_conninfo ci[48];
+ int i;
+
+ req.cnum = 48;
+ req.ci = ci;
+ if (ioctl(ctl, bnepgetconnlist, &req)) {
+ perror("Failed to get connection list");
+ return -1;
+ }
+
+ for (i=0; i < req.cnum; i++) {
+ struct bnep_conndel_req req;
+ memcpy(req.dst, ci[i].dst, ETH_ALEN);
+ req.flags = 0;
+ ioctl(ctl, bnepconndel, &req);
+ }
+ return 0;
+}
+
+static int bnep_connadd(int sk, uint16_t role, char *dev)
+{
+ struct bnep_connadd_req req;
+
+ strncpy(req.device, dev, 16);
+ req.device[15] = '\0';
+ req.sock = sk;
+ req.role = role;
+ if (ioctl(ctl, bnepconnadd, &req))
+ return -1;
+ strncpy(dev, req.device, 16);
+ return 0;
+}
+
+struct __service_16 {
+ uint16_t dst;
+ uint16_t src;
+} __attribute__ ((packed));
+
+struct __service_32 {
+ uint16_t unused1;
+ uint16_t dst;
+ uint16_t unused2;
+ uint16_t src;
+} __attribute__ ((packed));
+
+struct __service_128 {
+ uint16_t unused1;
+ uint16_t dst;
+ uint16_t unused2[8];
+ uint16_t src;
+ uint16_t unused3[7];
+} __attribute__ ((packed));
+
+int bnep_accept_connection(int sk, uint16_t role, char *dev)
+{
+ struct bnep_setup_conn_req *req;
+ struct bnep_control_rsp *rsp;
+ unsigned char pkt[BNEP_MTU];
+ int r;
+
+ r = recv(sk, pkt, BNEP_MTU, 0);
+ if (r <= 0)
+ return -1;
+
+ errno = EPROTO;
+
+ if (r < sizeof(*req))
+ return -1;
+
+ req = (void *) pkt;
+ if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
+ return -1;
+
+ /* FIXME: Check role UUIDs */
+
+ rsp = (void *) pkt;
+ rsp->type = BNEP_CONTROL;
+ rsp->ctrl = BNEP_SETUP_CONN_RSP;
+ rsp->resp = htons(BNEP_SUCCESS);
+ if (send(sk, rsp, sizeof(*rsp), 0) < 0)
+ return -1;
+
+ return bnep_connadd(sk, role, dev);
+}
+
+/* Create BNEP connection
+ * sk - Connect L2CAP socket
+ * role - Local role
+ * service - Remote service
+ * dev - Network device (contains actual dev name on return)
+ */
+int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev)
+{
+ struct bnep_setup_conn_req *req;
+ struct bnep_control_rsp *rsp;
+ struct __service_16 *s;
+ unsigned char pkt[BNEP_MTU];
+ int r;
+
+ /* Send request */
+ req = (void *) pkt;
+ req->type = BNEP_CONTROL;
+ req->ctrl = BNEP_SETUP_CONN_REQ;
+ req->uuid_size = 2; /* 16bit UUID */
+ s = (void *) req->service;
+ s->dst = htons(svc);
+ s->src = htons(role);
+
+ if (send(sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0)
+ return -1;
+
+receive:
+ /* Get response */
+ r = recv(sk, pkt, BNEP_MTU, 0);
+ if (r <= 0)
+ return -1;
+
+ errno = EPROTO;
+
+ if (r < sizeof(*rsp))
+ return -1;
+
+ rsp = (void *) pkt;
+ if (rsp->type != BNEP_CONTROL)
+ return -1;
+
+ if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
+ goto receive;
+
+ r = ntohs(rsp->resp);
+
+ switch (r) {
+ case BNEP_SUCCESS:
+ break;
+
+ case BNEP_CONN_INVALID_DST:
+ case BNEP_CONN_INVALID_SRC:
+ case BNEP_CONN_INVALID_SVC:
+ errno = EPROTO;
+ return -1;
+
+ case BNEP_CONN_NOT_ALLOWED:
+ errno = EACCES;
+ return -1;
+ }
+
+ return bnep_connadd(sk, role, dev);
+}
diff --git a/utils/pand/main.c b/utils/pand/main.c
new file mode 100644
index 00000000..ce3b8ebb
--- /dev/null
+++ b/utils/pand/main.c
@@ -0,0 +1,798 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/bnep.h>
+
+#include "pand.h"
+
+#ifdef NEED_PPOLL
+#include "ppoll.h"
+#endif
+
+static uint16_t role = BNEP_SVC_PANU; /* Local role (ie service) */
+static uint16_t service = BNEP_SVC_NAP; /* Remote service */
+
+static int detach = 1;
+static int persist;
+static int use_sdp = 1;
+static int use_cache;
+static int link_mode = 0;
+static int cleanup;
+static int search_duration = 10;
+
+static struct {
+ int valid;
+ char dst[40];
+ bdaddr_t bdaddr;
+} cache;
+
+static char netdev[16] = "bnep%d";
+static char *pidfile = NULL;
+static char *devupcmd = NULL;
+static char *devdowncmd = NULL;
+
+static bdaddr_t src_addr = *BDADDR_ANY;
+static int src_dev = -1;
+
+static volatile int terminate;
+
+static void do_kill(char *dst);
+
+enum {
+ NONE,
+ SHOW,
+ LISTEN,
+ CONNECT,
+ KILL
+} modes;
+
+struct script_arg {
+ char dev[20];
+ char dst[20];
+ int sk;
+ int nsk;
+};
+
+static void run_script(char *script, char *dev, char *dst, int sk, int nsk)
+{
+ char *argv[4];
+ struct sigaction sa;
+
+ if (!script)
+ return;
+
+ if (access(script, R_OK | X_OK))
+ return;
+
+ if (fork())
+ return;
+
+ if (sk >= 0)
+ close(sk);
+
+ if (nsk >= 0)
+ close(nsk);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ argv[0] = script;
+ argv[1] = dev;
+ argv[2] = dst;
+ argv[3] = NULL;
+
+ execv(script, argv);
+
+ exit(1);
+}
+
+/* Wait for disconnect or error condition on the socket */
+static int w4_hup(int sk, struct script_arg *down_cmd)
+{
+ struct pollfd pf;
+ sigset_t sigs;
+ int n;
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ while (!terminate) {
+ pf.fd = sk;
+ pf.events = POLLERR | POLLHUP;
+
+ n = ppoll(&pf, 1, NULL, &sigs);
+
+ if (n < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ syslog(LOG_ERR, "Poll failed. %s(%d)",
+ strerror(errno), errno);
+
+ return 1;
+ }
+
+ if (n) {
+ int err = 0;
+ socklen_t olen = sizeof(err);
+
+ getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &olen);
+
+ syslog(LOG_INFO, "%s disconnected%s%s", netdev,
+ err ? " : " : "", err ? strerror(err) : "");
+
+ if (down_cmd)
+ run_script(devdowncmd,
+ down_cmd->dev, down_cmd->dst,
+ down_cmd->sk, down_cmd->nsk);
+
+ close(sk);
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int do_listen(void)
+{
+ struct l2cap_options l2o;
+ struct sockaddr_l2 l2a;
+ socklen_t olen;
+ int sk, lm;
+
+ if (use_sdp)
+ bnep_sdp_register(&src_addr, role);
+
+ /* Create L2CAP socket and bind it to PSM BNEP */
+ sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Cannot create L2CAP socket. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ memset(&l2a, 0, sizeof(l2a));
+ l2a.l2_family = AF_BLUETOOTH;
+ bacpy(&l2a.l2_bdaddr, &src_addr);
+ l2a.l2_psm = htobs(BNEP_PSM);
+
+ if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a))) {
+ syslog(LOG_ERR, "Bind failed. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ /* Setup L2CAP options according to BNEP spec */
+ memset(&l2o, 0, sizeof(l2o));
+ olen = sizeof(l2o);
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen) < 0) {
+ syslog(LOG_ERR, "Failed to get L2CAP options. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ l2o.imtu = l2o.omtu = BNEP_MTU;
+ if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) {
+ syslog(LOG_ERR, "Failed to set L2CAP options. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ /* Set link mode */
+ lm = link_mode;
+ if (lm && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0) {
+ syslog(LOG_ERR, "Failed to set link mode. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ listen(sk, 10);
+
+ while (!terminate) {
+ socklen_t alen = sizeof(l2a);
+ char devname[16];
+ int nsk;
+
+ nsk = accept(sk, (struct sockaddr *) &l2a, &alen);
+ if (nsk < 0) {
+ syslog(LOG_ERR, "Accept failed. %s(%d)",
+ strerror(errno), errno);
+ continue;
+ }
+
+ switch (fork()) {
+ case 0:
+ break;
+ case -1:
+ syslog(LOG_ERR, "Fork failed. %s(%d)",
+ strerror(errno), errno);
+ default:
+ close(nsk);
+ continue;
+ }
+
+ strncpy(devname, netdev, 16);
+ devname[15] = '\0';
+
+ if (!bnep_accept_connection(nsk, role, devname)) {
+ char str[40];
+ struct script_arg down_cmd;
+
+ ba2str(&l2a.l2_bdaddr, str);
+
+ syslog(LOG_INFO, "New connection from %s at %s",
+ str, devname);
+
+ run_script(devupcmd, devname, str, sk, nsk);
+
+ memset(&down_cmd, 0, sizeof(struct script_arg));
+ strncpy(down_cmd.dev, devname, strlen(devname) + 1);
+ strncpy(down_cmd.dst, str, strlen(str) + 1);
+ down_cmd.sk = sk;
+ down_cmd.nsk = nsk;
+ w4_hup(nsk, &down_cmd);
+ } else {
+ syslog(LOG_ERR, "Connection failed. %s(%d)",
+ strerror(errno), errno);
+ }
+
+ close(nsk);
+ exit(0);
+ }
+
+ if (use_sdp)
+ bnep_sdp_unregister();
+
+ return 0;
+}
+
+/* Connect and initiate BNEP session
+ * Returns:
+ * -1 - critical error (exit persist mode)
+ * 1 - non critical error
+ * 0 - success
+ */
+static int create_connection(char *dst, bdaddr_t *bdaddr)
+{
+ struct l2cap_options l2o;
+ struct sockaddr_l2 l2a;
+ socklen_t olen;
+ int sk, r = 0;
+ struct script_arg down_cmd;
+
+ syslog(LOG_INFO, "Connecting to %s", dst);
+
+ sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Cannot create L2CAP socket. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ /* Setup L2CAP options according to BNEP spec */
+ memset(&l2o, 0, sizeof(l2o));
+ olen = sizeof(l2o);
+ getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen);
+ l2o.imtu = l2o.omtu = BNEP_MTU;
+ setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o));
+
+ memset(&l2a, 0, sizeof(l2a));
+ l2a.l2_family = AF_BLUETOOTH;
+ bacpy(&l2a.l2_bdaddr, &src_addr);
+
+ if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a)))
+ syslog(LOG_ERR, "Bind failed. %s(%d)",
+ strerror(errno), errno);
+
+ memset(&l2a, 0, sizeof(l2a));
+ l2a.l2_family = AF_BLUETOOTH;
+ bacpy(&l2a.l2_bdaddr, bdaddr);
+ l2a.l2_psm = htobs(BNEP_PSM);
+
+ if (!connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) &&
+ !bnep_create_connection(sk, role, service, netdev)) {
+
+ syslog(LOG_INFO, "%s connected", netdev);
+
+ run_script(devupcmd, netdev, dst, sk, -1);
+
+ if (persist || devdowncmd) {
+ memset(&down_cmd, 0, sizeof(struct script_arg));
+ strncpy(down_cmd.dev, netdev, strlen(netdev) + 1);
+ strncpy(down_cmd.dst, dst, strlen(dst) + 1);
+ down_cmd.sk = sk;
+ down_cmd.nsk = -1;
+ w4_hup(sk, &down_cmd);
+
+ if (terminate && cleanup) {
+ syslog(LOG_INFO, "Disconnecting from %s.", dst);
+ do_kill(dst);
+ }
+ }
+
+ r = 0;
+ } else {
+ syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
+ dst, strerror(errno), errno);
+ r = 1;
+ }
+
+ close(sk);
+
+ if (use_cache) {
+ if (!r) {
+ /* Succesesful connection, validate cache */
+ strcpy(cache.dst, dst);
+ bacpy(&cache.bdaddr, bdaddr);
+ cache.valid = use_cache;
+ } else
+ cache.valid--;
+ }
+
+ return r;
+}
+
+/* Search and connect
+ * Returns:
+ * -1 - critical error (exit persist mode)
+ * 1 - non critical error
+ * 0 - success
+ */
+static int do_connect(void)
+{
+ inquiry_info *ii;
+ int reconnect = 0;
+ int i, n, r = 0;
+
+ do {
+ if (reconnect)
+ sleep(persist);
+ reconnect = 1;
+
+ if (cache.valid > 0) {
+ /* Use cached bdaddr */
+ r = create_connection(cache.dst, &cache.bdaddr);
+ if (r < 0) {
+ terminate = 1;
+ break;
+ }
+ continue;
+ }
+
+ syslog(LOG_INFO, "Inquiring");
+
+ /* FIXME: Should we use non general LAP here ? */
+
+ ii = NULL;
+ n = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0);
+ if (n < 0) {
+ syslog(LOG_ERR, "Inquiry failed. %s(%d)",
+ strerror(errno), errno);
+ continue;
+ }
+
+ for (i = 0; i < n; i++) {
+ char dst[40];
+ ba2str(&ii[i].bdaddr, dst);
+
+ if (use_sdp) {
+ syslog(LOG_INFO, "Searching for %s on %s",
+ bnep_svc2str(service), dst);
+
+ if (bnep_sdp_search(&src_addr, &ii[i].bdaddr, service) <= 0)
+ continue;
+ }
+
+ r = create_connection(dst, &ii[i].bdaddr);
+ if (r < 0) {
+ terminate = 1;
+ break;
+ }
+ }
+ bt_free(ii);
+ } while (!terminate && persist);
+
+ return r;
+}
+
+static void do_show(void)
+{
+ bnep_show_connections();
+}
+
+static void do_kill(char *dst)
+{
+ if (dst)
+ bnep_kill_connection((void *) strtoba(dst));
+ else
+ bnep_kill_all_connections();
+}
+
+static void sig_hup(int sig)
+{
+ return;
+}
+
+static void sig_term(int sig)
+{
+ terminate = 1;
+}
+
+static int write_pidfile(void)
+{
+ int fd;
+ FILE *f;
+ pid_t pid;
+
+ do {
+ fd = open(pidfile, O_WRONLY|O_TRUNC|O_CREAT|O_EXCL, 0644);
+ if (fd == -1) {
+ /* Try to open the file for read. */
+ fd = open(pidfile, O_RDONLY);
+ if (fd < 0) {
+ syslog(LOG_ERR, "Could not read old pidfile: %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ /* We're already running; send a SIGHUP (we presume that they
+ * are calling ifup for a reason, so they probably want to
+ * rescan) and then exit cleanly and let things go on in the
+ * background. Muck with the filename so that we don't go
+ * deleting the pid file for the already-running instance.
+ */
+ f = fdopen(fd, "r");
+ if (!f) {
+ syslog(LOG_ERR, "Could not fdopen old pidfile: %s(%d)",
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ pid = 0;
+ if (fscanf(f, "%d", &pid) != 1)
+ pid = 0;
+ fclose(f);
+
+ if (pid) {
+ /* Try to kill it. */
+ if (kill(pid, SIGHUP) == -1) {
+ /* No such pid; remove the bogus pid file. */
+ syslog(LOG_INFO, "Removing stale pidfile");
+ unlink(pidfile);
+ fd = -1;
+ } else {
+ /* Got it. Don't mess with the pid file on
+ * our way out. */
+ syslog(LOG_INFO, "Signalling existing process %d and exiting\n", pid);
+ pidfile = NULL;
+ return -1;
+ }
+ }
+ }
+ } while(fd == -1);
+
+ f = fdopen(fd, "w");
+ if (!f) {
+ syslog(LOG_ERR, "Could not fdopen new pidfile: %s(%d)",
+ strerror(errno), errno);
+ close(fd);
+ unlink(pidfile);
+ return -1;
+ }
+
+ fprintf(f, "%d\n", getpid());
+ fclose(f);
+
+ return 0;
+}
+
+static struct option main_lopts[] = {
+ { "help", 0, 0, 'h' },
+ { "listen", 0, 0, 's' },
+ { "connect", 1, 0, 'c' },
+ { "search", 2, 0, 'Q' },
+ { "kill", 1, 0, 'k' },
+ { "killall", 0, 0, 'K' },
+ { "role", 1, 0, 'r' },
+ { "service", 1, 0, 'd' },
+ { "ethernet", 1, 0, 'e' },
+ { "device", 1, 0, 'i' },
+ { "nosdp", 0, 0, 'D' },
+ { "list", 0, 0, 'l' },
+ { "show", 0, 0, 'l' },
+ { "nodetach", 0, 0, 'n' },
+ { "persist", 2, 0, 'p' },
+ { "auth", 0, 0, 'A' },
+ { "encrypt", 0, 0, 'E' },
+ { "secure", 0, 0, 'S' },
+ { "master", 0, 0, 'M' },
+ { "cache", 0, 0, 'C' },
+ { "pidfile", 1, 0, 'P' },
+ { "devup", 1, 0, 'u' },
+ { "devdown", 1, 0, 'o' },
+ { "autozap", 0, 0, 'z' },
+ { 0, 0, 0, 0 }
+};
+
+static char main_sopts[] = "hsc:k:Kr:d:e:i:lnp::DQ::AESMC::P:u:o:z";
+
+static char main_help[] =
+ "Bluetooth PAN daemon version " VERSION " \n"
+ "Usage:\n"
+ "\tpand <options>\n"
+ "Options:\n"
+ "\t--show --list -l Show active PAN connections\n"
+ "\t--listen -s Listen for PAN connections\n"
+ "\t--connect -c <bdaddr> Create PAN connection\n"
+ "\t--autozap -z Disconnect automatically on exit\n"
+ "\t--search -Q[duration] Search and connect\n"
+ "\t--kill -k <bdaddr> Kill PAN connection\n"
+ "\t--killall -K Kill all PAN connections\n"
+ "\t--role -r <role> Local PAN role (PANU, NAP, GN)\n"
+ "\t--service -d <role> Remote PAN service (PANU, NAP, GN)\n"
+ "\t--ethernet -e <name> Network interface name\n"
+ "\t--device -i <bdaddr> Source bdaddr\n"
+ "\t--nosdp -D Disable SDP\n"
+ "\t--auth -A Enable authentication\n"
+ "\t--encrypt -E Enable encryption\n"
+ "\t--secure -S Secure connection\n"
+ "\t--master -M Become the master of a piconet\n"
+ "\t--nodetach -n Do not become a daemon\n"
+ "\t--persist -p[interval] Persist mode\n"
+ "\t--cache -C[valid] Cache addresses\n"
+ "\t--pidfile -P <pidfile> Create PID file\n"
+ "\t--devup -u <script> Script to run when interface comes up\n"
+ "\t--devdown -o <script> Script to run when interface comes down\n";
+
+int main(int argc, char *argv[])
+{
+ char *dst = NULL, *src = NULL;
+ struct sigaction sa;
+ int mode = NONE;
+ int opt;
+
+ while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
+ switch(opt) {
+ case 'l':
+ mode = SHOW;
+ detach = 0;
+ break;
+
+ case 's':
+ mode = LISTEN;
+ break;
+
+ case 'c':
+ mode = CONNECT;
+ dst = strdup(optarg);
+ break;
+
+ case 'Q':
+ mode = CONNECT;
+ if (optarg)
+ search_duration = atoi(optarg);
+ break;
+
+ case 'k':
+ mode = KILL;
+ detach = 0;
+ dst = strdup(optarg);
+ break;
+
+ case 'K':
+ mode = KILL;
+ detach = 0;
+ break;
+
+ case 'i':
+ src = strdup(optarg);
+ break;
+
+ case 'r':
+ bnep_str2svc(optarg, &role);
+ break;
+
+ case 'd':
+ bnep_str2svc(optarg, &service);
+ break;
+
+ case 'D':
+ use_sdp = 0;
+ break;
+
+ case 'A':
+ link_mode |= L2CAP_LM_AUTH;
+ break;
+
+ case 'E':
+ link_mode |= L2CAP_LM_ENCRYPT;
+ break;
+
+ case 'S':
+ link_mode |= L2CAP_LM_SECURE;
+ break;
+
+ case 'M':
+ link_mode |= L2CAP_LM_MASTER;
+ break;
+
+ case 'e':
+ strncpy(netdev, optarg, 16);
+ netdev[15] = '\0';
+ break;
+
+ case 'n':
+ detach = 0;
+ break;
+
+ case 'p':
+ if (optarg)
+ persist = atoi(optarg);
+ else
+ persist = 5;
+ break;
+
+ case 'C':
+ if (optarg)
+ use_cache = atoi(optarg);
+ else
+ use_cache = 2;
+ break;
+
+ case 'P':
+ pidfile = strdup(optarg);
+ break;
+
+ case 'u':
+ devupcmd = strdup(optarg);
+ break;
+
+ case 'o':
+ devdowncmd = strdup(optarg);
+ break;
+
+ case 'z':
+ cleanup = 1;
+ break;
+
+ case 'h':
+ default:
+ printf(main_help);
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (bnep_init())
+ return -1;
+
+ /* Check non daemon modes first */
+ switch (mode) {
+ case SHOW:
+ do_show();
+ return 0;
+
+ case KILL:
+ do_kill(dst);
+ return 0;
+
+ case NONE:
+ printf(main_help);
+ return 0;
+ }
+
+ /* Initialize signals */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ if (detach && daemon(0, 0)) {
+ perror("Can't start daemon");
+ exit(1);
+ }
+
+ openlog("pand", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
+ syslog(LOG_INFO, "Bluetooth PAN daemon version %s", VERSION);
+
+ if (src) {
+ src_dev = hci_devid(src);
+ if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
+ syslog(LOG_ERR, "Invalid source. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+ }
+
+ if (pidfile && write_pidfile())
+ return -1;
+
+ if (dst) {
+ /* Disable cache invalidation */
+ use_cache = 0;
+
+ strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
+ str2ba(dst, &cache.bdaddr);
+ cache.valid = 1;
+ free(dst);
+ }
+
+ switch (mode) {
+ case CONNECT:
+ do_connect();
+ break;
+
+ case LISTEN:
+ do_listen();
+ break;
+ }
+
+ if (pidfile)
+ unlink(pidfile);
+
+ return 0;
+}
diff --git a/utils/pand/pand.1 b/utils/pand/pand.1
new file mode 100644
index 00000000..4603b8bf
--- /dev/null
+++ b/utils/pand/pand.1
@@ -0,0 +1,77 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29.
+.TH BlueZ "1" "February 2003" "PAN daemon" "User Commands"
+.SH NAME
+pand \- BlueZ Bluetooth PAN daemon
+.SH DESCRIPTION
+The pand PAN daemon allows your computer to connect to ethernet
+networks using Bluetooth.
+.SH SYNPOSIS
+pand <options>
+.SH OPTIONS
+.TP
+\fB\-\-show\fR \fB\-\-list\fR \fB\-l\fR
+Show active PAN connections
+.TP
+\fB\-\-listen\fR \fB\-s\fR
+Listen for PAN connections
+.TP
+\fB\-\-connect\fR \fB\-c\fR <bdaddr>
+Create PAN connection
+.TP
+\fB\-\-search\fR \fB\-Q[duration]\fR
+Search and connect
+.TP
+\fB\-\-kill\fR \fB\-k\fR <bdaddr>
+Kill PAN connection
+.TP
+\fB\-\-killall\fR \fB\-K\fR
+Kill all PAN connections
+.TP
+\fB\-\-role\fR \fB\-r\fR <role>
+Local PAN role (PANU, NAP, GN)
+.TP
+\fB\-\-service\fR \fB\-d\fR <role>
+Remote PAN service (PANU, NAP, GN)
+.TP
+\fB\-\-ethernet\fR \fB\-e\fR <name>
+Network interface name
+.TP
+\fB\-\-device\fR \fB\-i\fR <bdaddr>
+Source bdaddr
+.TP
+\fB\-\-nosdp\fR \fB\-D\fR
+Disable SDP
+.TP
+\fB\-\-encrypt\fR \fB\-E\fR
+Enable encryption
+.TP
+\fB\-\-secure\fR \fB\-S\fR
+Secure connection
+.TP
+\fB\-\-master\fR \fB\-M\fR
+Become the master of a piconet
+.TP
+\fB\-\-nodetach\fR \fB\-n\fR
+Do not become a daemon
+.TP
+\fB\-\-persist\fR \fB\-p[interval]\fR
+Persist mode
+.TP
+\fB\-\-cache\fR \fB\-C[valid]\fR
+Cache addresses
+.TP
+\fB\-\-pidfile\fR \fB\-P <pidfile>\fR
+Create PID file
+.TP
+\fB\-\-devup\fR \fB\-u <script>\fR
+Script to run when interface comes up
+.TP
+\fB\-\-devdown\fR \fB\-o <script>\fR
+Script to run when interface comes down
+.TP
+\fB\-\-autozap\fR \fB\-z\fR
+Disconnect automatically on exit
+
+.SH SCRIPTS
+The devup/devdown script will be called with bluetooth device as first argument
+and bluetooth destination address as second argument.
diff --git a/utils/pand/pand.h b/utils/pand/pand.h
new file mode 100644
index 00000000..3e91f82d
--- /dev/null
+++ b/utils/pand/pand.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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
+ *
+ */
+
+/* BNEP functions */
+int bnep_init(void);
+int bnep_cleanup(void);
+
+int bnep_str2svc(char *svc, uint16_t *uuid);
+char *bnep_svc2str(uint16_t uuid);
+
+int bnep_show_connections(void);
+int bnep_kill_connection(uint8_t *dst);
+int bnep_kill_all_connections(void);
+
+int bnep_accept_connection(int sk, uint16_t role, char *dev);
+int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev);
+
+/* SDP functions */
+int bnep_sdp_register(bdaddr_t *device, uint16_t role);
+void bnep_sdp_unregister(void);
+int bnep_sdp_search(bdaddr_t *src, bdaddr_t *dst, uint16_t service);
diff --git a/utils/pand/sdp.c b/utils/pand/sdp.c
new file mode 100644
index 00000000..05e2e182
--- /dev/null
+++ b/utils/pand/sdp.c
@@ -0,0 +1,247 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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 <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/bnep.h>
+
+#include "pand.h"
+
+static sdp_record_t *record;
+static sdp_session_t *session;
+
+void bnep_sdp_unregister(void)
+{
+ if (record && sdp_record_unregister(session, record))
+ syslog(LOG_ERR, "Service record unregistration failed.");
+
+ sdp_close(session);
+}
+
+static void add_lang_attr(sdp_record_t *r)
+{
+ sdp_lang_attr_t base_lang;
+ sdp_list_t *langs = 0;
+
+ /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
+ base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
+ base_lang.encoding = 106;
+ base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
+ langs = sdp_list_append(0, &base_lang);
+ sdp_set_lang_attr(r, langs);
+ sdp_list_free(langs, 0);
+}
+
+int bnep_sdp_register(bdaddr_t *device, uint16_t role)
+{
+ sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
+ uuid_t root_uuid, pan, l2cap, bnep;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *proto[2];
+ sdp_data_t *v, *p;
+ uint16_t psm = 15, version = 0x0100;
+ uint16_t security_desc = 0;
+ uint16_t net_access_type = 0xfffe;
+ uint32_t max_net_access_rate = 0;
+ char *name = "BlueZ PAN";
+ char *desc = "BlueZ PAN Service";
+ int status;
+
+ session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
+ if (!session) {
+ syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ record = sdp_record_alloc();
+ if (!record) {
+ syslog(LOG_ERR, "Failed to allocate service record %s(%d)",
+ strerror(errno), errno);
+ sdp_close(session);
+ return -1;
+ }
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+ sdp_list_free(root, 0);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(NULL, &l2cap);
+ p = sdp_data_alloc(SDP_UINT16, &psm);
+ proto[0] = sdp_list_append(proto[0], p);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&bnep, BNEP_UUID);
+ proto[1] = sdp_list_append(NULL, &bnep);
+ v = sdp_data_alloc(SDP_UINT16, &version);
+ proto[1] = sdp_list_append(proto[1], v);
+
+ /* Supported protocols */
+ {
+ uint16_t ptype[4] = {
+ 0x0800, /* IPv4 */
+ 0x0806, /* ARP */
+ };
+ sdp_data_t *head, *pseq;
+ int p;
+
+ for (p = 0, head = NULL; p < 2; p++) {
+ sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
+ if (head)
+ sdp_seq_append(head, data);
+ else
+ head = data;
+ }
+ pseq = sdp_data_alloc(SDP_SEQ16, head);
+ proto[1] = sdp_list_append(proto[1], pseq);
+ }
+
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ add_lang_attr(record);
+
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(proto[1], NULL);
+ sdp_list_free(apseq, NULL);
+ sdp_list_free(aproto, NULL);
+ sdp_data_free(p);
+ sdp_data_free(v);
+ sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC, SDP_UINT16, &security_desc);
+
+ switch (role) {
+ case BNEP_SVC_NAP:
+ sdp_uuid16_create(&pan, NAP_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &pan);
+ sdp_set_service_classes(record, svclass);
+
+ sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_set_info_attr(record, "Network Access Point", name, desc);
+
+ sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE, SDP_UINT16, &net_access_type);
+ sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE, SDP_UINT32, &max_net_access_rate);
+ break;
+
+ case BNEP_SVC_GN:
+ sdp_uuid16_create(&pan, GN_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &pan);
+ sdp_set_service_classes(record, svclass);
+
+ sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_set_info_attr(record, "Group Network Service", name, desc);
+ break;
+
+ case BNEP_SVC_PANU:
+ sdp_uuid16_create(&pan, PANU_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &pan);
+ sdp_set_service_classes(record, svclass);
+ sdp_list_free(svclass, 0);
+
+ sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(record, pfseq);
+ sdp_list_free(pfseq, 0);
+
+ sdp_set_info_attr(record, "PAN User", name, desc);
+ break;
+ }
+
+ status = sdp_device_record_register(session, device, record, 0);
+ if (status) {
+ syslog(LOG_ERR, "SDP registration failed.");
+ sdp_record_free(record); record = NULL;
+ sdp_close(session);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Search for PAN service.
+ * Returns 1 if service is found and 0 otherwise. */
+int bnep_sdp_search(bdaddr_t *src, bdaddr_t *dst, uint16_t service)
+{
+ sdp_list_t *srch, *rsp = NULL;
+ sdp_session_t *s;
+ uuid_t svclass;
+ int err;
+
+ switch (service) {
+ case BNEP_SVC_PANU:
+ sdp_uuid16_create(&svclass, PANU_SVCLASS_ID);
+ break;
+ case BNEP_SVC_NAP:
+ sdp_uuid16_create(&svclass, NAP_SVCLASS_ID);
+ break;
+ case BNEP_SVC_GN:
+ sdp_uuid16_create(&svclass, GN_SVCLASS_ID);
+ break;
+ }
+
+ srch = sdp_list_append(NULL, &svclass);
+
+ s = sdp_connect(src, dst, 0);
+ if (!s) {
+ syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
+ strerror(errno), errno);
+ return 0;
+ }
+
+ err = sdp_service_search_req(s, srch, 1, &rsp);
+ sdp_close(s);
+
+ /* Assume that search is successeful
+ * if at least one record is found */
+ if (!err && sdp_list_len(rsp))
+ return 1;
+
+ return 0;
+}
diff --git a/utils/plugins/Makefile.am b/utils/plugins/Makefile.am
new file mode 100644
index 00000000..a8e833d0
--- /dev/null
+++ b/utils/plugins/Makefile.am
@@ -0,0 +1,43 @@
+
+plugindir = $(libdir)/bluetooth/plugins
+
+if NETLINK
+netlink_plugins = netlink.la
+else
+netlink_plugins =
+endif
+
+plugin_LTLIBRARIES = $(netlink_plugins)
+
+noinst_LTLIBRARIES = echo.la storage.la
+
+echo_la_SOURCES = echo.c
+
+storage_la_SOURCES = storage.c
+
+if NETLINK
+netlink_la_SOURCES = netlink.c
+
+netlink_la_LIBADD = @NETLINK_LIBS@
+endif
+
+AM_LDFLAGS = -module -avoid-version -no-undefined \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ @NETLINK_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid
+
+MAINTAINERCLEANFILES = Makefile.in
+
+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/utils/plugins/Makefile.in b/utils/plugins/Makefile.in
new file mode 100644
index 00000000..fd981f92
--- /dev/null
+++ b/utils/plugins/Makefile.in
@@ -0,0 +1,536 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plugins
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(plugindir)"
+pluginLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
+echo_la_LIBADD =
+am_echo_la_OBJECTS = echo.lo
+echo_la_OBJECTS = $(am_echo_la_OBJECTS)
+netlink_la_DEPENDENCIES =
+am__netlink_la_SOURCES_DIST = netlink.c
+@NETLINK_TRUE@am_netlink_la_OBJECTS = netlink.lo
+netlink_la_OBJECTS = $(am_netlink_la_OBJECTS)
+@NETLINK_TRUE@am_netlink_la_rpath = -rpath $(plugindir)
+storage_la_LIBADD =
+am_storage_la_OBJECTS = storage.lo
+storage_la_OBJECTS = $(am_storage_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(echo_la_SOURCES) $(netlink_la_SOURCES) \
+ $(storage_la_SOURCES)
+DIST_SOURCES = $(echo_la_SOURCES) $(am__netlink_la_SOURCES_DIST) \
+ $(storage_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugindir = $(libdir)/bluetooth/plugins
+@NETLINK_FALSE@netlink_plugins =
+@NETLINK_TRUE@netlink_plugins = netlink.la
+plugin_LTLIBRARIES = $(netlink_plugins)
+noinst_LTLIBRARIES = echo.la storage.la
+echo_la_SOURCES = echo.c
+storage_la_SOURCES = storage.c
+@NETLINK_TRUE@netlink_la_SOURCES = netlink.c
+@NETLINK_TRUE@netlink_la_LIBADD = @NETLINK_LIBS@
+AM_LDFLAGS = -module -avoid-version -no-undefined \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ @NETLINK_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plugins/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+echo.la: $(echo_la_OBJECTS) $(echo_la_DEPENDENCIES)
+ $(LINK) $(echo_la_OBJECTS) $(echo_la_LIBADD) $(LIBS)
+netlink.la: $(netlink_la_OBJECTS) $(netlink_la_DEPENDENCIES)
+ $(LINK) $(am_netlink_la_rpath) $(netlink_la_OBJECTS) $(netlink_la_LIBADD) $(LIBS)
+storage.la: $(storage_la_OBJECTS) $(storage_la_DEPENDENCIES)
+ $(LINK) $(storage_la_OBJECTS) $(storage_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/echo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) all-local
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local \
+ clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \
+ clean-generic clean-libtool clean-local \
+ clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-pluginLTLIBRARIES
+
+
+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
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/plugins/echo.c b/utils/plugins/echo.c
new file mode 100644
index 00000000..2c549089
--- /dev/null
+++ b/utils/plugins/echo.c
@@ -0,0 +1,162 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include <glib.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "server.h"
+#include "logging.h"
+
+static gboolean session_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ unsigned char buf[672];
+ gsize len, written;
+ GIOError err;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+ return FALSE;
+
+ err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+
+ g_io_channel_write(chan, (const gchar *) buf, len, &written);
+
+ return TRUE;
+}
+
+static gboolean connect_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ GIOChannel *io;
+ struct sockaddr_rc addr;
+ socklen_t optlen;
+ char address[18];
+ int sk, nsk;
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
+ if (nsk < 0)
+ return TRUE;
+
+ io = g_io_channel_unix_new(nsk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ ba2str(&addr.rc_bdaddr, address);
+
+ g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ session_event, NULL);
+
+ return TRUE;
+}
+
+static GIOChannel *setup_rfcomm(uint8_t channel)
+{
+ GIOChannel *io;
+ struct sockaddr_rc addr;
+ int sk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0)
+ return NULL;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, BDADDR_ANY);
+ addr.rc_channel = channel;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(sk);
+ return NULL;
+ }
+
+ if (listen(sk, 10) < 0) {
+ close(sk);
+ return NULL;
+ }
+
+ io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ g_io_add_watch(io, G_IO_IN, connect_event, NULL);
+
+ return io;
+}
+
+static GIOChannel *chan = NULL;
+
+static int echo_probe(const char *adapter)
+{
+ debug("echo probe adapter %s", adapter);
+
+ chan = setup_rfcomm(23);
+
+ return 0;
+}
+
+static void echo_remove(const char *adapter)
+{
+ debug("echo remove adapter %s", adapter);
+
+ g_io_channel_unref(chan);
+}
+
+static struct bt_server echo_server = {
+ .uuid = "00001101-0000-1000-8000-00805F9B34FB",
+ .probe = echo_probe,
+ .remove = echo_remove,
+};
+
+static int echo_init(void)
+{
+ debug("Setup echo plugin");
+
+ return bt_register_server(&echo_server);
+}
+
+static void echo_exit(void)
+{
+ debug("Cleanup echo plugin");
+
+ bt_unregister_server(&echo_server);
+}
+
+BLUETOOTH_PLUGIN_DEFINE("echo", echo_init, echo_exit)
diff --git a/utils/plugins/netlink.c b/utils/plugins/netlink.c
new file mode 100644
index 00000000..887b51ea
--- /dev/null
+++ b/utils/plugins/netlink.c
@@ -0,0 +1,126 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include <glib.h>
+
+#include "plugin.h"
+#include "logging.h"
+
+static struct nl_handle *handle;
+static struct nl_cache *cache;
+static struct genl_family *family;
+
+static GIOChannel *channel;
+
+static gboolean channel_callback(GIOChannel *chan,
+ GIOCondition cond, void *user_data)
+{
+ int err;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+ return FALSE;
+
+ debug("Message available on netlink channel");
+
+ err = nl_recvmsgs_default(handle);
+
+ return TRUE;
+}
+
+static int create_channel(int fd)
+{
+ channel = g_io_channel_unix_new(fd);
+ if (channel == NULL)
+ return -ENOMEM;
+
+ g_io_add_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ channel_callback, NULL);
+
+ return 0;
+}
+
+static int netlink_init(void)
+{
+ info("Starting experimental netlink support");
+
+ handle = nl_handle_alloc();
+ if (!handle) {
+ error("Failed to allocate netlink handle");
+ return -ENOMEM;
+ }
+
+ if (genl_connect(handle) < 0) {
+ error("Failed to connect to generic netlink");
+ nl_handle_destroy(handle);
+ return -ENOLINK;
+ }
+
+ cache = genl_ctrl_alloc_cache(handle);
+ if (!cache) {
+ error("Failed to allocate generic netlink cache");
+ return -ENOMEM;
+ nl_handle_destroy(handle);
+ }
+
+ family = genl_ctrl_search_by_name(cache, "bluetooth");
+ if (!family) {
+ error("Failed to find Bluetooth netlink family");
+ nl_cache_free(cache);
+ nl_handle_destroy(handle);
+ return -ENOENT;
+ }
+
+ if (create_channel(nl_socket_get_fd(handle)) < 0) {
+ error("Failed to create netlink IO channel");
+ genl_family_put(family);
+ nl_cache_free(cache);
+ nl_handle_destroy(handle);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void netlink_exit(void)
+{
+ g_io_channel_unref(channel);
+
+ genl_family_put(family);
+ nl_cache_free(cache);
+ nl_handle_destroy(handle);
+}
+
+BLUETOOTH_PLUGIN_DEFINE("netlink", netlink_init, netlink_exit)
diff --git a/utils/plugins/storage.c b/utils/plugins/storage.c
new file mode 100644
index 00000000..9e65a1ad
--- /dev/null
+++ b/utils/plugins/storage.c
@@ -0,0 +1,42 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <bluetooth/bluetooth.h>
+
+#include "plugin.h"
+#include "logging.h"
+
+static int storage_init(void)
+{
+ return 0;
+}
+
+static void storage_exit(void)
+{
+}
+
+BLUETOOTH_PLUGIN_DEFINE("storage", storage_init, storage_exit)
diff --git a/utils/rfcomm/Makefile.am b/utils/rfcomm/Makefile.am
new file mode 100644
index 00000000..9baa8e67
--- /dev/null
+++ b/utils/rfcomm/Makefile.am
@@ -0,0 +1,34 @@
+
+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/utils/rfcomm/Makefile.in b/utils/rfcomm/Makefile.in
new file mode 100644
index 00000000..4951bc48
--- /dev/null
+++ b/utils/rfcomm/Makefile.in
@@ -0,0 +1,603 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@TOOLS_TRUE@bin_PROGRAMS = rfcomm$(EXEEXT)
+subdir = rfcomm
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in lexer.c \
+ parser.c parser.h
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
+ "$(DESTDIR)$(confdir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__rfcomm_SOURCES_DIST = main.c parser.h parser.y lexer.l kword.h \
+ kword.c
+@TOOLS_TRUE@am_rfcomm_OBJECTS = main.$(OBJEXT) parser.$(OBJEXT) \
+@TOOLS_TRUE@ lexer.$(OBJEXT) kword.$(OBJEXT)
+rfcomm_OBJECTS = $(am_rfcomm_OBJECTS)
+rfcomm_DEPENDENCIES =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(LEX) $(LFLAGS) $(AM_LFLAGS)
+YLWRAP = $(top_srcdir)/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(YACC) $(YFLAGS) $(AM_YFLAGS)
+SOURCES = $(rfcomm_SOURCES)
+DIST_SOURCES = $(am__rfcomm_SOURCES_DIST)
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+confDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(conf_DATA)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@CONFIGFILES_TRUE@@TOOLS_TRUE@confdir = $(sysconfdir)/bluetooth
+@CONFIGFILES_TRUE@@TOOLS_TRUE@conf_DATA = rfcomm.conf
+@TOOLS_TRUE@rfcomm_SOURCES = main.c parser.h parser.y lexer.l kword.h kword.c
+@TOOLS_TRUE@rfcomm_LDADD = @BLUEZ_LIBS@
+AM_CFLAGS = @BLUEZ_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
+BUILT_SOURCES = parser.h
+@MANPAGES_TRUE@@TOOLS_TRUE@man_MANS = rfcomm.1
+AM_YFLAGS = -d
+CLEANFILES = lexer.c parser.c parser.h
+EXTRA_DIST = rfcomm.1 rfcomm.conf
+MAINTAINERCLEANFILES = Makefile.in
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu rfcomm/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu rfcomm/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+parser.h: parser.c
+ @if test ! -f $@; then \
+ rm -f parser.c; \
+ $(MAKE) $(AM_MAKEFLAGS) parser.c; \
+ else :; fi
+rfcomm$(EXEEXT): $(rfcomm_OBJECTS) $(rfcomm_DEPENDENCIES)
+ @rm -f rfcomm$(EXEEXT)
+ $(LINK) $(rfcomm_OBJECTS) $(rfcomm_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kword.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+.l.c:
+ $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+ $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(man1_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+install-confDATA: $(conf_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(confdir)" || $(MKDIR_P) "$(DESTDIR)$(confdir)"
+ @list='$(conf_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(confDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(confdir)/$$f'"; \
+ $(confDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(confdir)/$$f"; \
+ done
+
+uninstall-confDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(conf_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(confdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(confdir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(MANS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(confdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f lexer.c
+ -rm -f parser.c
+ -rm -f parser.h
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-confDATA install-man
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-confDATA uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-confDATA install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-man1 install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-confDATA uninstall-man uninstall-man1
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/rfcomm/kword.c b/utils/rfcomm/kword.c
new file mode 100644
index 00000000..020f790f
--- /dev/null
+++ b/utils/rfcomm/kword.c
@@ -0,0 +1,65 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 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 <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "kword.h"
+#include "parser.h"
+
+int lineno;
+
+struct keyword_t rfcomm_keyword[] = {
+ { "bind", K_BIND },
+ { "device", K_DEVICE },
+ { "channel", K_CHANNEL },
+ { "comment", K_COMMENT },
+
+ { "yes", K_YES },
+ { "no", K_NO },
+ { "enable", K_YES },
+ { "disable", K_NO },
+
+ { NULL , 0 }
+};
+
+int rfcomm_find_keyword(struct keyword_t *keyword, char *string)
+{
+ while (keyword->string) {
+ if (!strcmp(string, keyword->string))
+ return keyword->type;
+ keyword++;
+ }
+
+ return -1;
+}
+
+struct rfcomm_opts rfcomm_opts[RFCOMM_MAX_DEV];
diff --git a/utils/rfcomm/kword.h b/utils/rfcomm/kword.h
new file mode 100644
index 00000000..557441cb
--- /dev/null
+++ b/utils/rfcomm/kword.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 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
+ *
+ */
+
+extern int lineno;
+
+struct keyword_t {
+ char *string;
+ int type;
+};
+
+extern struct keyword_t rfcomm_keyword[];
+
+int rfcomm_find_keyword(struct keyword_t *keyword, char *string);
+
+#define MAXCOMMENTLEN 100
+
+struct rfcomm_opts {
+ int bind;
+ bdaddr_t bdaddr;
+ int channel;
+ char comment[MAXCOMMENTLEN + 1];
+};
+
+extern struct rfcomm_opts rfcomm_opts[RFCOMM_MAX_DEV];
+
+int rfcomm_read_config(char *filename);
diff --git a/utils/rfcomm/lexer.c b/utils/rfcomm/lexer.c
new file mode 100644
index 00000000..bc162369
--- /dev/null
+++ b/utils/rfcomm/lexer.c
@@ -0,0 +1,1828 @@
+
+#line 3 "lexer.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 9
+#define YY_END_OF_BUFFER 10
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[36] =
+ { 0,
+ 0, 0, 10, 8, 1, 7, 8, 8, 6, 3,
+ 6, 0, 4, 0, 2, 6, 3, 6, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 5, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 5, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 6, 1, 1, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 8, 1, 1,
+ 1, 1, 1, 1, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 1, 1, 1, 1, 6, 1, 9, 9, 9, 9,
+
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[10] =
+ { 0,
+ 1, 1, 2, 1, 1, 3, 4, 1, 4
+ } ;
+
+static yyconst flex_int16_t yy_base[49] =
+ { 0,
+ 0, 0, 46, 47, 47, 47, 41, 41, 0, 4,
+ 36, 38, 37, 37, 47, 0, 7, 31, 31, 0,
+ 0, 29, 0, 0, 28, 0, 0, 27, 0, 0,
+ 26, 0, 0, 47, 47, 15, 19, 21, 29, 28,
+ 27, 26, 25, 24, 23, 22, 13, 8
+ } ;
+
+static yyconst flex_int16_t yy_def[49] =
+ { 0,
+ 35, 1, 35, 35, 35, 35, 36, 37, 38, 35,
+ 10, 36, 36, 37, 35, 38, 38, 38, 38, 39,
+ 40, 35, 41, 42, 35, 43, 44, 35, 45, 46,
+ 35, 47, 48, 35, 0, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35
+ } ;
+
+static yyconst flex_int16_t yy_nxt[57] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 4, 11, 16,
+ 17, 34, 18, 19, 20, 12, 33, 12, 12, 14,
+ 14, 14, 14, 16, 16, 31, 30, 28, 27, 25,
+ 24, 22, 21, 32, 29, 26, 23, 19, 20, 15,
+ 13, 13, 18, 15, 13, 35, 3, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35
+ } ;
+
+static yyconst flex_int16_t yy_chk[57] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 10,
+ 10, 48, 10, 17, 17, 36, 47, 36, 36, 37,
+ 37, 37, 37, 38, 38, 46, 45, 44, 43, 42,
+ 41, 40, 39, 31, 28, 25, 22, 19, 18, 14,
+ 13, 12, 11, 8, 7, 3, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lexer.l"
+#line 2 "lexer.l"
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 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 <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "kword.h"
+#include "parser.h"
+
+
+#define ECHO {;}
+#define YY_DECL int yylex(void)
+
+int yyerror(char *str);
+
+#line 514 "lexer.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in (void );
+
+void yyset_in (FILE * in_str );
+
+FILE *yyget_out (void );
+
+void yyset_out (FILE * out_str );
+
+int yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ unsigned n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 58 "lexer.l"
+
+
+#line 697 "lexer.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 36 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 47 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 60 "lexer.l"
+{
+ /* Skip spaces and tabs */
+ ;
+ }
+ YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 65 "lexer.l"
+{
+ /* Skip comments */
+ lineno++;
+ }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 70 "lexer.l"
+{
+ yylval.number = atoi(yytext);
+ return NUMBER;
+ }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 75 "lexer.l"
+{
+ yylval.string = yytext;
+ return STRING;
+ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 80 "lexer.l"
+{
+ bdaddr_t *ba = malloc(sizeof(bdaddr_t));
+ str2ba(yytext, ba);
+ yylval.bdaddr = ba;
+ return BDADDR;
+ }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 87 "lexer.l"
+{
+ int keyword = rfcomm_find_keyword(rfcomm_keyword, yytext);
+ if (keyword != -1)
+ return keyword;
+
+ if (strncmp(yytext, "rfcomm", 6) == 0) {
+ yylval.number = atoi(yytext + 6);
+ return RFCOMM;
+ }
+
+ yylval.string = yytext;
+ return WORD;
+ }
+ YY_BREAK
+case 7:
+/* rule 7 can match eol */
+YY_RULE_SETUP
+#line 101 "lexer.l"
+{
+ lineno++;
+ }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 105 "lexer.l"
+{
+ return *yytext;
+ }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 109 "lexer.l"
+ECHO;
+ YY_BREAK
+#line 860 "lexer.c"
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 36 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 36 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 35);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 109 "lexer.l"
+
+
+
+int yywrap(void)
+{
+ return 1;
+}
+
diff --git a/utils/rfcomm/lexer.l b/utils/rfcomm/lexer.l
new file mode 100644
index 00000000..0c4dfee5
--- /dev/null
+++ b/utils/rfcomm/lexer.l
@@ -0,0 +1,114 @@
+%{
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 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 <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "kword.h"
+#include "parser.h"
+
+
+#define ECHO {;}
+#define YY_DECL int yylex(void)
+
+int yyerror(char *str);
+
+%}
+
+%option nounput
+
+space [ \t]
+linebreak \n
+comment \#.*\n
+keyword [A-Za-z0-9\_\-]+
+
+number [0-9]+
+string \".*\"
+bdaddr [A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}
+
+%%
+
+{space} {
+ /* Skip spaces and tabs */
+ ;
+ }
+
+{comment} {
+ /* Skip comments */
+ lineno++;
+ }
+
+{number} {
+ yylval.number = atoi(yytext);
+ return NUMBER;
+ }
+
+{string} {
+ yylval.string = yytext;
+ return STRING;
+ }
+
+{bdaddr} {
+ bdaddr_t *ba = malloc(sizeof(bdaddr_t));
+ str2ba(yytext, ba);
+ yylval.bdaddr = ba;
+ return BDADDR;
+ }
+
+{keyword} {
+ int keyword = rfcomm_find_keyword(rfcomm_keyword, yytext);
+ if (keyword != -1)
+ return keyword;
+
+ if (strncmp(yytext, "rfcomm", 6) == 0) {
+ yylval.number = atoi(yytext + 6);
+ return RFCOMM;
+ }
+
+ yylval.string = yytext;
+ return WORD;
+ }
+
+{linebreak} {
+ lineno++;
+ }
+
+. {
+ return *yytext;
+ }
+
+%%
+
+int yywrap(void)
+{
+ return 1;
+}
diff --git a/utils/rfcomm/main.c b/utils/rfcomm/main.c
new file mode 100644
index 00000000..f21e989c
--- /dev/null
+++ b/utils/rfcomm/main.c
@@ -0,0 +1,845 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/rfcomm.h>
+
+#include "kword.h"
+
+#ifdef NEED_PPOLL
+#include "ppoll.h"
+#endif
+
+static char *rfcomm_config_file = NULL;
+static int rfcomm_raw_tty = 0;
+static int auth = 0;
+static int encryption = 0;
+static int secure = 0;
+static int master = 0;
+static int linger = 0;
+
+static char *rfcomm_state[] = {
+ "unknown",
+ "connected",
+ "clean",
+ "bound",
+ "listening",
+ "connecting",
+ "connecting",
+ "config",
+ "disconnecting",
+ "closed"
+};
+
+static volatile sig_atomic_t __io_canceled = 0;
+
+static void sig_hup(int sig)
+{
+ return;
+}
+
+static void sig_term(int sig)
+{
+ __io_canceled = 1;
+}
+
+static char *rfcomm_flagstostr(uint32_t flags)
+{
+ static char str[100];
+ str[0] = 0;
+
+ strcat(str, "[");
+
+ if (flags & (1 << RFCOMM_REUSE_DLC))
+ strcat(str, "reuse-dlc ");
+
+ if (flags & (1 << RFCOMM_RELEASE_ONHUP))
+ strcat(str, "release-on-hup ");
+
+ if (flags & (1 << RFCOMM_TTY_ATTACHED))
+ strcat(str, "tty-attached");
+
+ strcat(str, "]");
+ return str;
+}
+
+static void print_dev_info(struct rfcomm_dev_info *di)
+{
+ char src[18], dst[18], addr[40];
+
+ ba2str(&di->src, src); ba2str(&di->dst, dst);
+
+ if (bacmp(&di->src, BDADDR_ANY) == 0)
+ sprintf(addr, "%s", dst);
+ else
+ sprintf(addr, "%s -> %s", src, dst);
+
+ printf("rfcomm%d: %s channel %d %s %s\n",
+ di->id, addr, di->channel,
+ rfcomm_state[di->state],
+ di->flags ? rfcomm_flagstostr(di->flags) : "");
+}
+
+static void print_dev_list(int ctl, int flags)
+{
+ struct rfcomm_dev_list_req *dl;
+ struct rfcomm_dev_info *di;
+ int i;
+
+ dl = malloc(sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
+ if (!dl) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ dl->dev_num = RFCOMM_MAX_DEV;
+ di = dl->dev_info;
+
+ if (ioctl(ctl, RFCOMMGETDEVLIST, (void *) dl) < 0) {
+ perror("Can't get device list");
+ exit(1);
+ }
+
+ for (i = 0; i < dl->dev_num; i++)
+ print_dev_info(di + i);
+}
+
+static int create_dev(int ctl, int dev, uint32_t flags, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ struct rfcomm_dev_req req;
+ int err;
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+ req.flags = flags;
+ bacpy(&req.src, bdaddr);
+
+ if (argc < 2) {
+ err = rfcomm_read_config(rfcomm_config_file);
+ if (err < 0) {
+ perror("Can't open RFCOMM config file");
+ return err;
+ }
+
+ bacpy(&req.dst, &rfcomm_opts[dev].bdaddr);
+ req.channel = rfcomm_opts[dev].channel;
+
+ if (bacmp(&req.dst, BDADDR_ANY) == 0) {
+ fprintf(stderr, "Can't find a config entry for rfcomm%d\n", dev);
+ return -EFAULT;
+ }
+ } else {
+ str2ba(argv[1], &req.dst);
+
+ if (argc > 2)
+ req.channel = atoi(argv[2]);
+ else
+ req.channel = 1;
+ }
+
+ err = ioctl(ctl, RFCOMMCREATEDEV, &req);
+ if (err == EOPNOTSUPP)
+ fprintf(stderr, "RFCOMM TTY support not available\n");
+ else if (err < 0)
+ perror("Can't create device");
+
+ return err;
+}
+
+static int create_all(int ctl)
+{
+ struct rfcomm_dev_req req;
+ int i, err;
+
+ err = rfcomm_read_config(rfcomm_config_file);
+ if (err < 0) {
+ perror("Can't open RFCOMM config file");
+ return err;
+ }
+
+ for (i = 0; i < RFCOMM_MAX_DEV; i++) {
+ if (!rfcomm_opts[i].bind)
+ continue;
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = i;
+ req.flags = 0;
+ bacpy(&req.src, BDADDR_ANY);
+ bacpy(&req.dst, &rfcomm_opts[i].bdaddr);
+ req.channel = rfcomm_opts[i].channel;
+
+ if (bacmp(&req.dst, BDADDR_ANY) != 0)
+ ioctl(ctl, RFCOMMCREATEDEV, &req);
+ }
+
+ return 0;
+}
+
+static int release_dev(int ctl, int dev, uint32_t flags)
+{
+ struct rfcomm_dev_req req;
+ int err;
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+
+ err = ioctl(ctl, RFCOMMRELEASEDEV, &req);
+ if (err < 0)
+ perror("Can't release device");
+
+ return err;
+}
+
+static int release_all(int ctl)
+{
+ struct rfcomm_dev_list_req *dl;
+ struct rfcomm_dev_info *di;
+ int i;
+
+ dl = malloc(sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
+ if (!dl) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ dl->dev_num = RFCOMM_MAX_DEV;
+ di = dl->dev_info;
+
+ if (ioctl(ctl, RFCOMMGETDEVLIST, (void *) dl) < 0) {
+ perror("Can't get device list");
+ exit(1);
+ }
+
+ for (i = 0; i < dl->dev_num; i++)
+ release_dev(ctl, (di + i)->id, 0);
+
+ return 0;
+}
+
+static void run_cmdline(struct pollfd *p, sigset_t* sigs, char *devname,
+ int argc, char **argv)
+{
+ int i;
+ pid_t pid;
+ char **cmdargv;
+
+ cmdargv = malloc((argc + 1) * sizeof(char*));
+ if (!cmdargv)
+ return;
+
+ for (i = 0; i < argc; i++)
+ cmdargv[i] = (strcmp(argv[i], "{}") == 0) ? devname : argv[i];
+ cmdargv[i] = NULL;
+
+ pid = fork();
+
+ switch (pid) {
+ case 0:
+ i = execvp(cmdargv[0], cmdargv);
+ fprintf(stderr, "Couldn't execute command %s (errno=%d:%s)\n",
+ cmdargv[0], errno, strerror(errno));
+ break;
+ case -1:
+ fprintf(stderr, "Couldn't fork to execute command %s\n",
+ cmdargv[0]);
+ break;
+ default:
+ while (1) {
+ int status;
+ pid_t child;
+ struct timespec ts;
+
+ child = waitpid(-1, &status, WNOHANG);
+ if (child == pid || (child < 0 && errno != EAGAIN))
+ break;
+
+ p->revents = 0;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 200;
+ if (ppoll(p, 1, &ts, sigs) || __io_canceled) {
+ kill(pid, SIGTERM);
+ waitpid(pid, &status, 0);
+ break;
+ }
+ }
+ break;
+ }
+
+ free(cmdargv);
+}
+
+static void cmd_connect(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ struct sockaddr_rc laddr, raddr;
+ struct rfcomm_dev_req req;
+ struct termios ti;
+ struct sigaction sa;
+ struct pollfd p;
+ sigset_t sigs;
+ socklen_t alen;
+ char dst[18], devname[MAXPATHLEN];
+ int sk, fd, try = 30;
+
+ laddr.rc_family = AF_BLUETOOTH;
+ bacpy(&laddr.rc_bdaddr, bdaddr);
+ laddr.rc_channel = 0;
+
+ if (argc < 2) {
+ if (rfcomm_read_config(rfcomm_config_file) < 0) {
+ perror("Can't open RFCOMM config file");
+ return;
+ }
+
+ raddr.rc_family = AF_BLUETOOTH;
+ bacpy(&raddr.rc_bdaddr, &rfcomm_opts[dev].bdaddr);
+ raddr.rc_channel = rfcomm_opts[dev].channel;
+
+ if (bacmp(&raddr.rc_bdaddr, BDADDR_ANY) == 0) {
+ fprintf(stderr, "Can't find a config entry for rfcomm%d\n", dev);
+ return;
+ }
+ } else {
+ raddr.rc_family = AF_BLUETOOTH;
+ str2ba(argv[1], &raddr.rc_bdaddr);
+
+ if (argc > 2)
+ raddr.rc_channel = atoi(argv[2]);
+ else
+ raddr.rc_channel = 1;
+ }
+
+ sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ perror("Can't create RFCOMM socket");
+ return;
+ }
+
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ perror("Can't set linger option");
+ return;
+ }
+ }
+
+ if (bind(sk, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) {
+ perror("Can't bind RFCOMM socket");
+ close(sk);
+ return;
+ }
+
+ if (connect(sk, (struct sockaddr *) &raddr, sizeof(raddr)) < 0) {
+ perror("Can't connect RFCOMM socket");
+ close(sk);
+ return;
+ }
+
+ alen = sizeof(laddr);
+ if (getsockname(sk, (struct sockaddr *)&laddr, &alen) < 0) {
+ perror("Can't get RFCOMM socket name");
+ close(sk);
+ return;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+ req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP);
+
+ bacpy(&req.src, &laddr.rc_bdaddr);
+ bacpy(&req.dst, &raddr.rc_bdaddr);
+ req.channel = raddr.rc_channel;
+
+ dev = ioctl(sk, RFCOMMCREATEDEV, &req);
+ if (dev < 0) {
+ perror("Can't create RFCOMM TTY");
+ close(sk);
+ return;
+ }
+
+ snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
+ while ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+ if (errno == EACCES) {
+ perror("Can't open RFCOMM device");
+ goto release;
+ }
+
+ snprintf(devname, MAXPATHLEN - 1, "/dev/bluetooth/rfcomm/%d", dev);
+ if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+ if (try--) {
+ snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
+ usleep(100 * 1000);
+ continue;
+ }
+ perror("Can't open RFCOMM device");
+ goto release;
+ }
+ }
+
+ if (rfcomm_raw_tty) {
+ tcflush(fd, TCIOFLUSH);
+
+ cfmakeraw(&ti);
+ tcsetattr(fd, TCSANOW, &ti);
+ }
+
+ close(sk);
+
+ ba2str(&req.dst, dst);
+ printf("Connected %s to %s on channel %d\n", devname, dst, req.channel);
+ printf("Press CTRL-C for hangup\n");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ p.fd = fd;
+ p.events = POLLERR | POLLHUP;
+
+ while (!__io_canceled) {
+ p.revents = 0;
+ if (ppoll(&p, 1, NULL, &sigs) > 0)
+ break;
+ }
+
+ printf("Disconnected\n");
+
+ close(fd);
+ return;
+
+release:
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+ req.flags = (1 << RFCOMM_HANGUP_NOW);
+ ioctl(ctl, RFCOMMRELEASEDEV, &req);
+
+ close(sk);
+}
+
+static void cmd_listen(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ struct sockaddr_rc laddr, raddr;
+ struct rfcomm_dev_req req;
+ struct termios ti;
+ struct sigaction sa;
+ struct pollfd p;
+ sigset_t sigs;
+ socklen_t alen;
+ char dst[18], devname[MAXPATHLEN];
+ int sk, nsk, fd, lm, try = 30;
+
+ laddr.rc_family = AF_BLUETOOTH;
+ bacpy(&laddr.rc_bdaddr, bdaddr);
+ laddr.rc_channel = (argc < 2) ? 1 : atoi(argv[1]);
+
+ sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ perror("Can't create RFCOMM socket");
+ return;
+ }
+
+ lm = 0;
+ if (master)
+ lm |= RFCOMM_LM_MASTER;
+ if (auth)
+ lm |= RFCOMM_LM_AUTH;
+ if (encryption)
+ lm |= RFCOMM_LM_ENCRYPT;
+ if (secure)
+ lm |= RFCOMM_LM_SECURE;
+
+ if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
+ perror("Can't set RFCOMM link mode");
+ close(sk);
+ return;
+ }
+
+ if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
+ perror("Can't bind RFCOMM socket");
+ close(sk);
+ return;
+ }
+
+ printf("Waiting for connection on channel %d\n", laddr.rc_channel);
+
+ listen(sk, 10);
+
+ alen = sizeof(raddr);
+ nsk = accept(sk, (struct sockaddr *) &raddr, &alen);
+
+ alen = sizeof(laddr);
+ if (getsockname(nsk, (struct sockaddr *)&laddr, &alen) < 0) {
+ perror("Can't get RFCOMM socket name");
+ close(nsk);
+ return;
+ }
+
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ perror("Can't set linger option");
+ close(nsk);
+ return;
+ }
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+ req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP);
+
+ bacpy(&req.src, &laddr.rc_bdaddr);
+ bacpy(&req.dst, &raddr.rc_bdaddr);
+ req.channel = raddr.rc_channel;
+
+ dev = ioctl(nsk, RFCOMMCREATEDEV, &req);
+ if (dev < 0) {
+ perror("Can't create RFCOMM TTY");
+ close(sk);
+ return;
+ }
+
+ snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
+ while ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+ if (errno == EACCES) {
+ perror("Can't open RFCOMM device");
+ goto release;
+ }
+
+ snprintf(devname, MAXPATHLEN - 1, "/dev/bluetooth/rfcomm/%d", dev);
+ if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+ if (try--) {
+ snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
+ usleep(100);
+ continue;
+ }
+ perror("Can't open RFCOMM device");
+ goto release;
+ }
+ }
+
+ if (rfcomm_raw_tty) {
+ tcflush(fd, TCIOFLUSH);
+
+ cfmakeraw(&ti);
+ tcsetattr(fd, TCSANOW, &ti);
+ }
+
+ close(sk);
+ close(nsk);
+
+ ba2str(&req.dst, dst);
+ printf("Connection from %s to %s\n", dst, devname);
+ printf("Press CTRL-C for hangup\n");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ p.fd = fd;
+ p.events = POLLERR | POLLHUP;
+
+ if (argc <= 2) {
+ while (!__io_canceled) {
+ p.revents = 0;
+ if (ppoll(&p, 1, NULL, &sigs) > 0)
+ break;
+ }
+ } else
+ run_cmdline(&p, &sigs, devname, argc - 2, argv + 2);
+
+ sa.sa_handler = NULL;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ printf("Disconnected\n");
+
+ close(fd);
+ return;
+
+release:
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+ req.flags = (1 << RFCOMM_HANGUP_NOW);
+ ioctl(ctl, RFCOMMRELEASEDEV, &req);
+
+ close(sk);
+}
+
+static void cmd_watch(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ while (!__io_canceled) {
+ cmd_listen(ctl, dev, bdaddr, argc, argv);
+ usleep(10000);
+ }
+}
+
+static void cmd_create(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ if (strcmp(argv[0], "all") == 0)
+ create_all(ctl);
+ else
+ create_dev(ctl, dev, 0, bdaddr, argc, argv);
+}
+
+static void cmd_release(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ if (strcmp(argv[0], "all") == 0)
+ release_all(ctl);
+ else
+ release_dev(ctl, dev, 0);
+}
+
+static void cmd_show(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ if (strcmp(argv[0], "all") == 0)
+ print_dev_list(ctl, 0);
+ else {
+ struct rfcomm_dev_info di = { id: atoi(argv[0]) };
+ if (ioctl(ctl, RFCOMMGETDEVINFO, &di) < 0) {
+ perror("Get info failed");
+ exit(1);
+ }
+
+ print_dev_info(&di);
+ }
+}
+
+struct {
+ char *cmd;
+ char *alt;
+ void (*func)(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv);
+ char *opt;
+ char *doc;
+} command[] = {
+ { "bind", "create", cmd_create, "<dev> <bdaddr> [channel]", "Bind device" },
+ { "release", "unbind", cmd_release, "<dev>", "Release device" },
+ { "show", "info", cmd_show, "<dev>", "Show device" },
+ { "connect", "conn", cmd_connect, "<dev> <bdaddr> [channel]", "Connect device" },
+ { "listen", "server", cmd_listen, "<dev> [channel [cmd]]", "Listen" },
+ { "watch", "watch", cmd_watch, "<dev> [channel [cmd]]", "Watch" },
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static void usage(void)
+{
+ int i;
+
+ printf("RFCOMM configuration utility ver %s\n", VERSION);
+
+ printf("Usage:\n"
+ "\trfcomm [options] <command> <dev>\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-i [hciX|bdaddr] Local HCI device or BD Address\n"
+ "\t-h, --help Display help\n"
+ "\t-r, --raw Switch TTY into raw mode\n"
+ "\t-A, --auth Enable authentication\n"
+ "\t-E, --encrypt Enable encryption\n"
+ "\t-S, --secure Secure connection\n"
+ "\t-M, --master Become the master of a piconet\n"
+ "\t-f, --config [file] Specify alternate config file\n"
+ "\t-a Show all devices (default)\n"
+ "\n");
+
+ printf("Commands:\n");
+ for (i = 0; command[i].cmd; i++)
+ printf("\t%-8s %-24s\t%s\n",
+ command[i].cmd,
+ command[i].opt ? command[i].opt : " ",
+ command[i].doc);
+ printf("\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device", 1, 0, 'i' },
+ { "config", 1, 0, 'f' },
+ { "raw", 0, 0, 'r' },
+ { "auth", 0, 0, 'A' },
+ { "encrypt", 0, 0, 'E' },
+ { "secure", 0, 0, 'S' },
+ { "master", 0, 0, 'M' },
+ { "linger", 1, 0, 'L' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ bdaddr_t bdaddr;
+ int i, opt, ctl, dev_id, show_all = 0;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt = getopt_long(argc, argv, "+i:f:rahAESML:", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'i':
+ if (strncmp(optarg, "hci", 3) == 0)
+ hci_devba(atoi(optarg + 3), &bdaddr);
+ else
+ str2ba(optarg, &bdaddr);
+ break;
+
+ case 'f':
+ rfcomm_config_file = strdup(optarg);
+ break;
+
+ case 'r':
+ rfcomm_raw_tty = 1;
+ break;
+
+ case 'a':
+ show_all = 1;
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+
+ case 'A':
+ auth = 1;
+ break;
+
+ case 'E':
+ encryption = 1;
+ break;
+
+ case 'S':
+ secure = 1;
+ break;
+
+ case 'M':
+ master = 1;
+ break;
+
+ case 'L':
+ linger = atoi(optarg);
+ break;
+
+ default:
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 2) {
+ if (argc != 0) {
+ usage();
+ exit(1);
+ } else
+ show_all = 1;
+ }
+
+ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
+ if (ctl < 0) {
+ perror("Can't open RFCOMM control socket");
+ exit(1);
+ }
+
+ if (show_all) {
+ print_dev_list(ctl, 0);
+ close(ctl);
+ exit(0);
+ }
+
+ if (strncmp(argv[1], "/dev/rfcomm", 11) == 0)
+ dev_id = atoi(argv[1] + 11);
+ else if (strncmp(argv[1], "rfcomm", 6) == 0)
+ dev_id = atoi(argv[1] + 6);
+ else
+ dev_id = atoi(argv[1]);
+
+ for (i = 0; command[i].cmd; i++) {
+ if (strncmp(command[i].cmd, argv[0], 4) && strncmp(command[i].alt, argv[0], 4))
+ continue;
+ argc--;
+ argv++;
+ command[i].func(ctl, dev_id, &bdaddr, argc, argv);
+ close(ctl);
+ exit(0);
+ }
+
+ usage();
+
+ close(ctl);
+
+ return 0;
+}
diff --git a/utils/rfcomm/parser.c b/utils/rfcomm/parser.c
new file mode 100644
index 00000000..6ddaad82
--- /dev/null
+++ b/utils/rfcomm/parser.c
@@ -0,0 +1,1736 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ K_BIND = 258,
+ K_DEVICE = 259,
+ K_CHANNEL = 260,
+ K_COMMENT = 261,
+ K_YES = 262,
+ K_NO = 263,
+ NUMBER = 264,
+ RFCOMM = 265,
+ STRING = 266,
+ WORD = 267,
+ BDADDR = 268
+ };
+#endif
+/* Tokens. */
+#define K_BIND 258
+#define K_DEVICE 259
+#define K_CHANNEL 260
+#define K_COMMENT 261
+#define K_YES 262
+#define K_NO 263
+#define NUMBER 264
+#define RFCOMM 265
+#define STRING 266
+#define WORD 267
+#define BDADDR 268
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "parser.y"
+
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "kword.h"
+
+int yyparse(void);
+int yylex(void);
+int yyerror(char *s);
+
+struct rfcomm_opts *opts;
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 50 "parser.y"
+{
+ int number;
+ char *string;
+ bdaddr_t *bdaddr;
+}
+/* Line 187 of yacc.c. */
+#line 177 "parser.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 190 "parser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 8
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 40
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 17
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 8
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 20
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 33
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 268
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 16,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 14, 2, 15, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 4, 6, 9, 14, 19, 21, 23,
+ 25, 27, 30, 33, 37, 40, 43, 46, 49, 51,
+ 53
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 18, 0, -1, -1, 19, -1, 18, 19, -1, 20,
+ 14, 22, 15, -1, 21, 14, 22, 15, -1, 12,
+ -1, 1, -1, 12, -1, 10, -1, 23, 16, -1,
+ 1, 16, -1, 22, 23, 16, -1, 3, 24, -1,
+ 4, 13, -1, 5, 9, -1, 6, 11, -1, 12,
+ -1, 7, -1, 8, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 67, 67, 68, 69, 72, 73, 74, 77, 84,
+ 90, 99, 100, 101, 104, 109, 114, 119, 124, 130,
+ 131
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "K_BIND", "K_DEVICE", "K_CHANNEL",
+ "K_COMMENT", "K_YES", "K_NO", "NUMBER", "RFCOMM", "STRING", "WORD",
+ "BDADDR", "'{'", "'}'", "';'", "$accept", "config", "statement",
+ "section", "rfcomm", "rfcomm_options", "rfcomm_option", "bool", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 123, 125, 59
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 17, 18, 18, 18, 19, 19, 19, 19, 20,
+ 21, 22, 22, 22, 23, 23, 23, 23, 23, 24,
+ 24
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 1, 2, 4, 4, 1, 1, 1,
+ 1, 2, 2, 3, 2, 2, 2, 2, 1, 1,
+ 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 8, 10, 7, 0, 3, 0, 0, 1, 4,
+ 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
+ 0, 12, 19, 20, 14, 15, 16, 17, 5, 0,
+ 11, 6, 13
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 4, 5, 6, 7, 18, 19, 24
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -7
+static const yytype_int8 yypact[] =
+{
+ 10, -7, -7, -6, 14, -7, 4, 7, -7, -7,
+ 24, 24, 15, 25, 21, 26, 12, -7, -3, 22,
+ 1, -7, -7, -7, -7, -7, -7, -7, -7, 23,
+ -7, -7, -7
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -7, -7, 33, -7, -7, 29, -1, -7
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -10
+static const yytype_int8 yytable[] =
+{
+ 13, 14, 15, 16, 13, 14, 15, 16, -9, 17,
+ -2, 1, 28, 17, 8, 1, 31, 29, 10, 29,
+ 2, 11, 3, 27, 2, 12, 3, 13, 14, 15,
+ 16, 21, 22, 23, 25, 26, 17, 9, 30, 32,
+ 20
+};
+
+static const yytype_uint8 yycheck[] =
+{
+ 3, 4, 5, 6, 3, 4, 5, 6, 14, 12,
+ 0, 1, 15, 12, 0, 1, 15, 18, 14, 20,
+ 10, 14, 12, 11, 10, 1, 12, 3, 4, 5,
+ 6, 16, 7, 8, 13, 9, 12, 4, 16, 16,
+ 11
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 1, 10, 12, 18, 19, 20, 21, 0, 19,
+ 14, 14, 1, 3, 4, 5, 6, 12, 22, 23,
+ 22, 16, 7, 8, 24, 13, 9, 11, 15, 23,
+ 16, 15, 16
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 7:
+#line 75 "parser.y"
+ {
+ }
+ break;
+
+ case 8:
+#line 78 "parser.y"
+ {
+ yyclearin;
+ yyerrok;
+ }
+ break;
+
+ case 9:
+#line 85 "parser.y"
+ {
+ opts = NULL;
+ }
+ break;
+
+ case 10:
+#line 91 "parser.y"
+ {
+ if (((yyvsp[(1) - (1)].number) >= 0) && ((yyvsp[(1) - (1)].number) < RFCOMM_MAX_DEV))
+ opts = &rfcomm_opts[(yyvsp[(1) - (1)].number)];
+ else
+ opts = NULL;
+ }
+ break;
+
+ case 14:
+#line 105 "parser.y"
+ {
+ if (opts)
+ opts->bind = (yyvsp[(2) - (2)].number);
+ }
+ break;
+
+ case 15:
+#line 110 "parser.y"
+ {
+ if (opts)
+ bacpy(&opts->bdaddr, (yyvsp[(2) - (2)].bdaddr));
+ }
+ break;
+
+ case 16:
+#line 115 "parser.y"
+ {
+ if (opts)
+ opts->channel = (yyvsp[(2) - (2)].number);
+ }
+ break;
+
+ case 17:
+#line 120 "parser.y"
+ {
+ if (opts)
+ snprintf(opts->comment, MAXCOMMENTLEN, "%s", (yyvsp[(2) - (2)].string));
+ }
+ break;
+
+ case 18:
+#line 125 "parser.y"
+ {
+ // Unknown option
+ }
+ break;
+
+ case 19:
+#line 130 "parser.y"
+ { (yyval.number) = 1; }
+ break;
+
+ case 20:
+#line 131 "parser.y"
+ { (yyval.number) = 0; }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 1483 "parser.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 134 "parser.y"
+
+
+int yyerror(char *s)
+{
+ fprintf(stderr, "%s line %d\n", s, lineno);
+ return 0;
+}
+
+int rfcomm_read_config(char *filename)
+{
+ extern FILE *yyin;
+ char file[MAXPATHLEN + 1];
+ int i;
+
+ for (i = 0; i < RFCOMM_MAX_DEV; i++) {
+ rfcomm_opts[i].bind = 0;
+ bacpy(&rfcomm_opts[i].bdaddr, BDADDR_ANY);
+ rfcomm_opts[i].channel = 1;
+ }
+
+ if (filename) {
+ snprintf(file, MAXPATHLEN, "%s", filename);
+ } else {
+ snprintf(file, MAXPATHLEN, "%s/.bluetooth/rfcomm.conf", getenv("HOME"));
+
+ if ((getuid() == 0) || (access(file, R_OK) < 0))
+ snprintf(file, MAXPATHLEN, "%s/rfcomm.conf", CONFIGDIR);
+ }
+
+ if (!(yyin = fopen(file, "r")))
+ return -1;
+
+ lineno = 1;
+ yyparse();
+
+ fclose(yyin);
+
+ return 0;
+}
+
diff --git a/utils/rfcomm/parser.h b/utils/rfcomm/parser.h
new file mode 100644
index 00000000..7a1951f4
--- /dev/null
+++ b/utils/rfcomm/parser.h
@@ -0,0 +1,88 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ K_BIND = 258,
+ K_DEVICE = 259,
+ K_CHANNEL = 260,
+ K_COMMENT = 261,
+ K_YES = 262,
+ K_NO = 263,
+ NUMBER = 264,
+ RFCOMM = 265,
+ STRING = 266,
+ WORD = 267,
+ BDADDR = 268
+ };
+#endif
+/* Tokens. */
+#define K_BIND 258
+#define K_DEVICE 259
+#define K_CHANNEL 260
+#define K_COMMENT 261
+#define K_YES 262
+#define K_NO 263
+#define NUMBER 264
+#define RFCOMM 265
+#define STRING 266
+#define WORD 267
+#define BDADDR 268
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 50 "parser.y"
+{
+ int number;
+ char *string;
+ bdaddr_t *bdaddr;
+}
+/* Line 1489 of yacc.c. */
+#line 81 "parser.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/utils/rfcomm/parser.y b/utils/rfcomm/parser.y
new file mode 100644
index 00000000..3afec076
--- /dev/null
+++ b/utils/rfcomm/parser.y
@@ -0,0 +1,172 @@
+%{
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "kword.h"
+
+int yyparse(void);
+int yylex(void);
+int yyerror(char *s);
+
+struct rfcomm_opts *opts;
+
+%}
+
+%union {
+ int number;
+ char *string;
+ bdaddr_t *bdaddr;
+}
+
+%token K_BIND K_DEVICE K_CHANNEL K_COMMENT
+%token K_YES K_NO
+
+%token <number> NUMBER RFCOMM
+%token <string> STRING WORD
+%token <bdaddr> BDADDR
+
+%type <number> bool
+
+%%
+
+config :
+ | statement
+ | config statement
+ ;
+
+statement : section '{' rfcomm_options '}'
+ | rfcomm '{' rfcomm_options '}'
+ | WORD
+ {
+ }
+ | error
+ {
+ yyclearin;
+ yyerrok;
+ }
+ ;
+
+section : WORD
+ {
+ opts = NULL;
+ }
+ ;
+
+rfcomm : RFCOMM
+ {
+ if (($1 >= 0) && ($1 < RFCOMM_MAX_DEV))
+ opts = &rfcomm_opts[$1];
+ else
+ opts = NULL;
+ }
+ ;
+
+rfcomm_options : rfcomm_option ';'
+ | error ';'
+ | rfcomm_options rfcomm_option ';'
+ ;
+
+rfcomm_option : K_BIND bool
+ {
+ if (opts)
+ opts->bind = $2;
+ }
+ | K_DEVICE BDADDR
+ {
+ if (opts)
+ bacpy(&opts->bdaddr, $2);
+ }
+ | K_CHANNEL NUMBER
+ {
+ if (opts)
+ opts->channel = $2;
+ }
+ | K_COMMENT STRING
+ {
+ if (opts)
+ snprintf(opts->comment, MAXCOMMENTLEN, "%s", $2);
+ }
+ | WORD
+ {
+ // Unknown option
+ }
+ ;
+
+bool : K_YES { $$ = 1; }
+ | K_NO { $$ = 0; }
+ ;
+
+%%
+
+int yyerror(char *s)
+{
+ fprintf(stderr, "%s line %d\n", s, lineno);
+ return 0;
+}
+
+int rfcomm_read_config(char *filename)
+{
+ extern FILE *yyin;
+ char file[MAXPATHLEN + 1];
+ int i;
+
+ for (i = 0; i < RFCOMM_MAX_DEV; i++) {
+ rfcomm_opts[i].bind = 0;
+ bacpy(&rfcomm_opts[i].bdaddr, BDADDR_ANY);
+ rfcomm_opts[i].channel = 1;
+ }
+
+ if (filename) {
+ snprintf(file, MAXPATHLEN, "%s", filename);
+ } else {
+ snprintf(file, MAXPATHLEN, "%s/.bluetooth/rfcomm.conf", getenv("HOME"));
+
+ if ((getuid() == 0) || (access(file, R_OK) < 0))
+ snprintf(file, MAXPATHLEN, "%s/rfcomm.conf", CONFIGDIR);
+ }
+
+ if (!(yyin = fopen(file, "r")))
+ return -1;
+
+ lineno = 1;
+ yyparse();
+
+ fclose(yyin);
+
+ return 0;
+}
diff --git a/utils/rfcomm/rfcomm.1 b/utils/rfcomm/rfcomm.1
new file mode 100644
index 00000000..eaec05df
--- /dev/null
+++ b/utils/rfcomm/rfcomm.1
@@ -0,0 +1,137 @@
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.TH RFCOMM 1 "APRIL 28, 2002" "" ""
+
+.SH NAME
+rfcomm \- RFCOMM configuration utility
+.SH SYNOPSIS
+.BR "rfcomm
+[
+.I options
+] <
+.I command
+> <
+.I dev
+>
+.SH DESCRIPTION
+.B rfcomm
+is used to set up, maintain, and inspect the RFCOMM configuration
+of the Bluetooth subsystem in the Linux kernel. If no
+.B command
+is given, or if the option
+.B -a
+is used,
+.B rfcomm
+prints information about the configured RFCOMM devices.
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible commands.
+.TP
+.BI -a
+Prints information about all configured RFCOMM devices.
+.TP
+.BI -r
+Switch TTY into raw mode (doesn't work with "bind").
+.TP
+.BI -f " <file>"
+Specify alternate config file.
+.TP
+.BI -i " <hciX> | <bdaddr>"
+The command is applied to device
+.BI -A
+Enable authentication.
+.BI -E
+Enable encryption.
+.BI -S
+Secure connection.
+.BI -M
+Become the master of a piconet.
+.I
+hciX
+, which must be the name or the address of an installed Bluetooth
+device. If not specified, the command will be use the first
+available Bluetooth device.
+.TP
+.BI -A
+Enable authentification
+.TP
+.BI -E
+Enable encryption
+.TP
+.BI -S
+Secure connection
+.TP
+.BI -M
+Become the master of a piconet
+.TP
+.BI -L " <seconds>"
+Set linger timeout
+.SH COMMANDS
+.TP
+.BI show " <dev>"
+Display the information about the specified device.
+.TP
+.BI connect " <dev> [bdaddr] [channel]"
+Connect the RFCOMM device to the remote Bluetooth device on the
+specified channel. If no channel is specified, it will use the
+channel number 1. If also the Bluetooth address is left out, it
+tries to read the data from the config file. This command can
+be terminated with the key sequence CTRL-C.
+.TP
+.BI listen " <dev> [channel] [cmd]"
+Listen on a specified RFCOMM channel for incoming connections.
+If no channel is specified, it will use the channel number 1, but
+a channel must be specified before cmd. If cmd is given, it will be
+executed as soon as a client connects. When the child process
+terminates or the client disconnect, the command will terminate.
+Occurences of {} in cmd will be replaced by the name of the device
+used by the connection. This command can be terminated with the key
+sequence CTRL-C.
+.TP
+.BI watch " <dev> [channel] [cmd]"
+Watch is identical to
+.B listen
+except that when the child process terminates or the client
+disconnect, the command will restart listening with the same
+parameters.
+.TP
+.BI bind " <dev> [bdaddr] [channel]"
+This binds the RFCOMM device to a remote Bluetooth device. The
+command did not establish a connection to the remote device, it
+only creates the binding. The connection will be established right
+after an application tries to open the RFCOMM device. If no channel
+number is specified, it uses the channel number 1. If the Bluetooth
+address is also left out, it tries to read the data from the config
+file.
+
+If
+.B all
+is specified for the RFCOMM device, then all devices that have
+.B "bind yes"
+set in the config will be bound.
+.TP
+.BI release " <dev>"
+This command releases a defined RFCOMM binding.
+
+If
+.B all
+is specified for the RFCOMM device, then all bindings will be removed.
+This command didn't care about the settings in the config file.
+.SH AUTHOR
+Written by Marcel Holtmann <marcel@holtmann.org>.
+.br
diff --git a/utils/rfcomm/rfcomm.conf b/utils/rfcomm/rfcomm.conf
new file mode 100644
index 00000000..6179ef7b
--- /dev/null
+++ b/utils/rfcomm/rfcomm.conf
@@ -0,0 +1,17 @@
+#
+# RFCOMM configuration file.
+#
+
+#rfcomm0 {
+# # Automatically bind the device at startup
+# bind no;
+#
+# # Bluetooth address of the device
+# device 11:22:33:44:55:66;
+#
+# # RFCOMM channel for the connection
+# channel 1;
+#
+# # Description of the connection
+# comment "Example Bluetooth device";
+#}
diff --git a/utils/sbc/Makefile.am b/utils/sbc/Makefile.am
new file mode 100644
index 00000000..9079305a
--- /dev/null
+++ b/utils/sbc/Makefile.am
@@ -0,0 +1,28 @@
+
+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
+
+libsbc_la_CFLAGS = -finline-functions -funswitch-loops -fgcse-after-reload
+
+noinst_PROGRAMS = sbcinfo sbcdec sbcenc $(sndfile_programs)
+
+sbcdec_LDADD = libsbc.la
+
+sbcenc_LDADD = libsbc.la
+
+if SNDFILE
+sbctester_LDADD = @SNDFILE_LIBS@
+endif
+endif
+
+AM_CFLAGS = @SNDFILE_CFLAGS@
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/sbc/Makefile.in b/utils/sbc/Makefile.in
new file mode 100644
index 00000000..400f68ef
--- /dev/null
+++ b/utils/sbc/Makefile.in
@@ -0,0 +1,516 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@SBC_TRUE@noinst_PROGRAMS = sbcinfo$(EXEEXT) sbcdec$(EXEEXT) \
+@SBC_TRUE@ sbcenc$(EXEEXT) $(am__EXEEXT_1)
+subdir = sbc
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsbc_la_LIBADD =
+am__libsbc_la_SOURCES_DIST = sbc.h sbc.c sbc_math.h sbc_tables.h
+@SBC_TRUE@am_libsbc_la_OBJECTS = libsbc_la-sbc.lo
+libsbc_la_OBJECTS = $(am_libsbc_la_OBJECTS)
+libsbc_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libsbc_la_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+@SBC_TRUE@am_libsbc_la_rpath =
+@SNDFILE_TRUE@am__EXEEXT_1 = sbctester$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+sbcdec_SOURCES = sbcdec.c
+sbcdec_OBJECTS = sbcdec.$(OBJEXT)
+@SBC_TRUE@sbcdec_DEPENDENCIES = libsbc.la
+sbcenc_SOURCES = sbcenc.c
+sbcenc_OBJECTS = sbcenc.$(OBJEXT)
+@SBC_TRUE@sbcenc_DEPENDENCIES = libsbc.la
+sbcinfo_SOURCES = sbcinfo.c
+sbcinfo_OBJECTS = sbcinfo.$(OBJEXT)
+sbcinfo_LDADD = $(LDADD)
+sbctester_SOURCES = sbctester.c
+sbctester_OBJECTS = sbctester.$(OBJEXT)
+sbctester_DEPENDENCIES =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libsbc_la_SOURCES) sbcdec.c sbcenc.c sbcinfo.c sbctester.c
+DIST_SOURCES = $(am__libsbc_la_SOURCES_DIST) sbcdec.c sbcenc.c \
+ sbcinfo.c sbctester.c
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@SNDFILE_FALSE@sndfile_programs =
+@SNDFILE_TRUE@sndfile_programs = sbctester
+@SBC_TRUE@noinst_LTLIBRARIES = libsbc.la
+@SBC_TRUE@libsbc_la_SOURCES = sbc.h sbc.c sbc_math.h sbc_tables.h
+@SBC_TRUE@libsbc_la_CFLAGS = -finline-functions -funswitch-loops -fgcse-after-reload
+@SBC_TRUE@sbcdec_LDADD = libsbc.la
+@SBC_TRUE@sbcenc_LDADD = libsbc.la
+@SBC_TRUE@@SNDFILE_TRUE@sbctester_LDADD = @SNDFILE_LIBS@
+AM_CFLAGS = @SNDFILE_CFLAGS@
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu sbc/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu sbc/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libsbc.la: $(libsbc_la_OBJECTS) $(libsbc_la_DEPENDENCIES)
+ $(libsbc_la_LINK) $(am_libsbc_la_rpath) $(libsbc_la_OBJECTS) $(libsbc_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+sbcdec$(EXEEXT): $(sbcdec_OBJECTS) $(sbcdec_DEPENDENCIES)
+ @rm -f sbcdec$(EXEEXT)
+ $(LINK) $(sbcdec_OBJECTS) $(sbcdec_LDADD) $(LIBS)
+sbcenc$(EXEEXT): $(sbcenc_OBJECTS) $(sbcenc_DEPENDENCIES)
+ @rm -f sbcenc$(EXEEXT)
+ $(LINK) $(sbcenc_OBJECTS) $(sbcenc_LDADD) $(LIBS)
+sbcinfo$(EXEEXT): $(sbcinfo_OBJECTS) $(sbcinfo_DEPENDENCIES)
+ @rm -f sbcinfo$(EXEEXT)
+ $(LINK) $(sbcinfo_OBJECTS) $(sbcinfo_LDADD) $(LIBS)
+sbctester$(EXEEXT): $(sbctester_OBJECTS) $(sbctester_DEPENDENCIES)
+ @rm -f sbctester$(EXEEXT)
+ $(LINK) $(sbctester_OBJECTS) $(sbctester_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsbc_la-sbc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbcdec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbcenc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbcinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbctester.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libsbc_la-sbc.lo: sbc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsbc_la_CFLAGS) $(CFLAGS) -MT libsbc_la-sbc.lo -MD -MP -MF $(DEPDIR)/libsbc_la-sbc.Tpo -c -o libsbc_la-sbc.lo `test -f 'sbc.c' || echo '$(srcdir)/'`sbc.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libsbc_la-sbc.Tpo $(DEPDIR)/libsbc_la-sbc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sbc.c' object='libsbc_la-sbc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsbc_la_CFLAGS) $(CFLAGS) -c -o libsbc_la-sbc.lo `test -f 'sbc.c' || echo '$(srcdir)/'`sbc.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ ctags distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/sbc/sbc.c b/utils/sbc/sbc.c
new file mode 100644
index 00000000..6303421f
--- /dev/null
+++ b/utils/sbc/sbc.c
@@ -0,0 +1,1411 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/* todo items:
+
+ use a log2 table for byte integer scale factors calculation (sum log2 results
+ for high and low bytes) fill bitpool by 16 bits instead of one at a time in
+ bits allocation/bitpool generation port to the dsp
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc.h"
+
+#define SBC_SYNCWORD 0x9C
+
+/* This structure contains an unpacked SBC frame.
+ Yes, there is probably quite some unused space herein */
+struct sbc_frame {
+ uint8_t frequency;
+ uint8_t block_mode;
+ uint8_t blocks;
+ enum {
+ MONO = SBC_MODE_MONO,
+ DUAL_CHANNEL = SBC_MODE_DUAL_CHANNEL,
+ STEREO = SBC_MODE_STEREO,
+ JOINT_STEREO = SBC_MODE_JOINT_STEREO
+ } mode;
+ uint8_t channels;
+ enum {
+ LOUDNESS = SBC_AM_LOUDNESS,
+ SNR = SBC_AM_SNR
+ } allocation;
+ uint8_t subband_mode;
+ uint8_t subbands;
+ uint8_t bitpool;
+ uint8_t codesize;
+ uint8_t length;
+
+ /* bit number x set means joint stereo has been used in subband x */
+ uint8_t joint;
+
+ /* only the lower 4 bits of every element are to be used */
+ uint8_t scale_factor[2][8];
+
+ /* raw integer subband samples in the frame */
+
+ int32_t sb_sample_f[16][2][8];
+ int32_t sb_sample[16][2][8]; /* modified subband samples */
+ int16_t pcm_sample[2][16*8]; /* original pcm audio samples */
+};
+
+struct sbc_decoder_state {
+ int subbands;
+ int32_t V[2][170];
+ int offset[2][16];
+};
+
+struct sbc_encoder_state {
+ int subbands;
+ int position[2];
+ int32_t X[2][160];
+};
+
+/*
+ * Calculates the CRC-8 of the first len bits in data
+ */
+static const uint8_t crc_table[256] = {
+ 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
+ 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
+ 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
+ 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
+ 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
+ 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
+ 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
+ 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
+ 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
+ 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
+ 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
+ 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
+ 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
+ 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
+ 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
+ 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
+ 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
+ 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
+ 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
+ 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
+ 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
+ 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
+ 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
+ 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
+ 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
+ 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
+ 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
+ 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
+ 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
+ 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
+ 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
+ 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
+};
+
+static uint8_t sbc_crc8(const uint8_t *data, size_t len)
+{
+ uint8_t crc = 0x0f;
+ size_t i;
+ uint8_t octet;
+
+ for (i = 0; i < len / 8; i++)
+ crc = crc_table[crc ^ data[i]];
+
+ octet = data[i];
+ for (i = 0; i < len % 8; i++) {
+ char bit = ((octet ^ crc) & 0x80) >> 7;
+
+ crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
+
+ octet = octet << 1;
+ }
+
+ return crc;
+}
+
+/*
+ * Code straight from the spec to calculate the bits array
+ * Takes a pointer to the frame in question, a pointer to the bits array and
+ * the sampling frequency (as 2 bit integer)
+ */
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+ uint8_t sf = frame->frequency;
+
+ if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ max_bitneed = 0;
+ if (frame->allocation == SNR) {
+ for (sb = 0; sb < frame->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++) {
+ if (frame->scale_factor[ch][sb] == 0)
+ bitneed[ch][sb] = -5;
+ else {
+ if (frame->subbands == 4)
+ loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+ else
+ loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+ if (loudness > 0)
+ bitneed[ch][sb] = loudness / 2;
+ else
+ bitneed[ch][sb] = loudness;
+ }
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+
+ bitcount = 0;
+ slicecount = 0;
+ bitslice = max_bitneed + 1;
+ do {
+ bitslice--;
+ bitcount += slicecount;
+ slicecount = 0;
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+ slicecount++;
+ else if (bitneed[ch][sb] == bitslice + 1)
+ slicecount += 2;
+ }
+ } while (bitcount + slicecount < frame->bitpool);
+
+ if (bitcount + slicecount == frame->bitpool) {
+ bitcount += slicecount;
+ bitslice--;
+ }
+
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (bitneed[ch][sb] < bitslice + 2)
+ bits[ch][sb] = 0;
+ else {
+ bits[ch][sb] = bitneed[ch][sb] - bitslice;
+ if (bits[ch][sb] > 16)
+ bits[ch][sb] = 16;
+ }
+ }
+
+ for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
+ bits[ch][sb]++;
+ bitcount++;
+ } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
+ bits[ch][sb] = 2;
+ bitcount += 2;
+ }
+ }
+
+ for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ if (bits[ch][sb] < 16) {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ }
+
+ }
+
+ } else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ max_bitneed = 0;
+ if (frame->allocation == SNR) {
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ bitneed[ch][sb] = frame->scale_factor[ch][sb];
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+ } else {
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (frame->scale_factor[ch][sb] == 0)
+ bitneed[ch][sb] = -5;
+ else {
+ if (frame->subbands == 4)
+ loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+ else
+ loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+ if (loudness > 0)
+ bitneed[ch][sb] = loudness / 2;
+ else
+ bitneed[ch][sb] = loudness;
+ }
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+ }
+
+ bitcount = 0;
+ slicecount = 0;
+ bitslice = max_bitneed + 1;
+ do {
+ bitslice--;
+ bitcount += slicecount;
+ slicecount = 0;
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+ slicecount++;
+ else if (bitneed[ch][sb] == bitslice + 1)
+ slicecount += 2;
+ }
+ }
+ } while (bitcount + slicecount < frame->bitpool);
+
+ if (bitcount + slicecount == frame->bitpool) {
+ bitcount += slicecount;
+ bitslice--;
+ }
+
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (bitneed[ch][sb] < bitslice + 2) {
+ bits[ch][sb] = 0;
+ } else {
+ bits[ch][sb] = bitneed[ch][sb] - bitslice;
+ if (bits[ch][sb] > 16)
+ bits[ch][sb] = 16;
+ }
+ }
+ }
+
+ ch = 0;
+ sb = 0;
+ while (bitcount < frame->bitpool) {
+ if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
+ bits[ch][sb]++;
+ bitcount++;
+ } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
+ bits[ch][sb] = 2;
+ bitcount += 2;
+ }
+ if (ch == 1) {
+ ch = 0;
+ sb++;
+ if (sb >= frame->subbands) break;
+ } else
+ ch = 1;
+ }
+
+ ch = 0;
+ sb = 0;
+ while (bitcount < frame->bitpool) {
+ if (bits[ch][sb] < 16) {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ if (ch == 1) {
+ ch = 0;
+ sb++;
+ if (sb >= frame->subbands) break;
+ } else
+ ch = 1;
+ }
+
+ }
+
+}
+
+/*
+ * Unpacks a SBC frame at the beginning of the stream in data,
+ * which has at most len bytes into frame.
+ * Returns the length in bytes of the packed frame, or a negative
+ * value on error. The error codes are:
+ *
+ * -1 Data stream too short
+ * -2 Sync byte incorrect
+ * -3 CRC8 incorrect
+ * -4 Bitpool value out of bounds
+ */
+static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
+ size_t len)
+{
+ int consumed;
+ /* Will copy the parts of the header that are relevant to crc
+ * calculation here */
+ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int crc_pos = 0;
+ int32_t temp;
+
+ int audio_sample;
+ int ch, sb, blk, bit; /* channel, subband, block and bit standard
+ counters */
+ int bits[2][8]; /* bits distribution */
+ uint32_t levels[2][8]; /* levels derived from that */
+
+ if (len < 4)
+ return -1;
+
+ if (data[0] != SBC_SYNCWORD)
+ return -2;
+
+ frame->frequency = (data[1] >> 6) & 0x03;
+
+ frame->block_mode = (data[1] >> 4) & 0x03;
+ switch (frame->block_mode) {
+ case SBC_BLK_4:
+ frame->blocks = 4;
+ break;
+ case SBC_BLK_8:
+ frame->blocks = 8;
+ break;
+ case SBC_BLK_12:
+ frame->blocks = 12;
+ break;
+ case SBC_BLK_16:
+ frame->blocks = 16;
+ break;
+ }
+
+ frame->mode = (data[1] >> 2) & 0x03;
+ switch (frame->mode) {
+ case MONO:
+ frame->channels = 1;
+ break;
+ case DUAL_CHANNEL: /* fall-through */
+ case STEREO:
+ case JOINT_STEREO:
+ frame->channels = 2;
+ break;
+ }
+
+ frame->allocation = (data[1] >> 1) & 0x01;
+
+ frame->subband_mode = (data[1] & 0x01);
+ frame->subbands = frame->subband_mode ? 8 : 4;
+
+ frame->bitpool = data[2];
+
+ if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+ frame->bitpool > 16 * frame->subbands)
+ return -4;
+
+ if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+ frame->bitpool > 32 * frame->subbands)
+ return -4;
+
+ /* data[3] is crc, we're checking it later */
+
+ consumed = 32;
+
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+ crc_pos = 16;
+
+ if (frame->mode == JOINT_STEREO) {
+ if (len * 8 < consumed + frame->subbands)
+ return -1;
+
+ frame->joint = 0x00;
+ for (sb = 0; sb < frame->subbands - 1; sb++)
+ frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb;
+ if (frame->subbands == 4)
+ crc_header[crc_pos / 8] = data[4] & 0xf0;
+ else
+ crc_header[crc_pos / 8] = data[4];
+
+ consumed += frame->subbands;
+ crc_pos += frame->subbands;
+ }
+
+ if (len * 8 < consumed + (4 * frame->subbands * frame->channels))
+ return -1;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ /* FIXME assert(consumed % 4 == 0); */
+ frame->scale_factor[ch][sb] =
+ (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F;
+ crc_header[crc_pos >> 3] |=
+ frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7));
+
+ consumed += 4;
+ crc_pos += 4;
+ }
+ }
+
+ if (data[3] != sbc_crc8(crc_header, crc_pos))
+ return -3;
+
+ sbc_calculate_bits(frame, bits);
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++)
+ levels[ch][sb] = (1 << bits[ch][sb]) - 1;
+ }
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (levels[ch][sb] > 0) {
+ audio_sample = 0;
+ for (bit = 0; bit < bits[ch][sb]; bit++) {
+ if (consumed > len * 8)
+ return -1;
+
+ if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
+ audio_sample |= 1 << (bits[ch][sb] - bit - 1);
+
+ consumed++;
+ }
+
+ frame->sb_sample[blk][ch][sb] =
+ (((audio_sample << 1) | 1) << frame->scale_factor[ch][sb]) /
+ levels[ch][sb] - (1 << frame->scale_factor[ch][sb]);
+ } else
+ frame->sb_sample[blk][ch][sb] = 0;
+ }
+ }
+ }
+
+ if (frame->mode == JOINT_STEREO) {
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (frame->joint & (0x01 << sb)) {
+ temp = frame->sb_sample[blk][0][sb] +
+ frame->sb_sample[blk][1][sb];
+ frame->sb_sample[blk][1][sb] =
+ frame->sb_sample[blk][0][sb] -
+ frame->sb_sample[blk][1][sb];
+ frame->sb_sample[blk][0][sb] = temp;
+ }
+ }
+ }
+ }
+
+ if ((consumed & 0x7) != 0)
+ consumed += 8 - (consumed & 0x7);
+
+ return consumed >> 3;
+}
+
+static void sbc_decoder_init(struct sbc_decoder_state *state,
+ const struct sbc_frame *frame)
+{
+ int i, ch;
+
+ memset(state->V, 0, sizeof(state->V));
+ state->subbands = frame->subbands;
+
+ for (ch = 0; ch < 2; ch++)
+ for (i = 0; i < frame->subbands * 2; i++)
+ state->offset[ch][i] = (10 * i + 10);
+}
+
+static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, k, idx;
+ int32_t *v = state->V[ch];
+ int *offset = state->offset[ch];
+
+ for (i = 0; i < 8; i++) {
+ /* Shifting */
+ offset[i]--;
+ if (offset[i] < 0) {
+ offset[i] = 79;
+ memcpy(v + 80, v, 9 * sizeof(*v));
+ }
+
+ /* Distribute the new matrix value to the shifted position */
+ v[offset[i]] = SCALE4_STAGED1(
+ MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0],
+ MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1],
+ MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2],
+ MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3])))));
+ }
+
+ /* Compute the samples */
+ for (idx = 0, i = 0; i < 4; i++, idx += 5) {
+ k = (i + 4) & 0xf;
+
+ /* Store in output, Q0 */
+ frame->pcm_sample[ch][blk * 4 + i] = SCALE4_STAGED2(
+ MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
+ MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
+ MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
+ MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1],
+ MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2],
+ MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2],
+ MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
+ MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
+ MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
+ MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4])))))))))));
+ }
+}
+
+static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, j, k, idx;
+ int *offset = state->offset[ch];
+
+ for (i = 0; i < 16; i++) {
+ /* Shifting */
+ offset[i]--;
+ if (offset[i] < 0) {
+ offset[i] = 159;
+ for (j = 0; j < 9; j++)
+ state->V[ch][j + 160] = state->V[ch][j];
+ }
+
+ /* Distribute the new matrix value to the shifted position */
+ state->V[ch][offset[i]] = SCALE8_STAGED1(
+ MULA(synmatrix8[i][0], frame->sb_sample[blk][ch][0],
+ MULA(synmatrix8[i][1], frame->sb_sample[blk][ch][1],
+ MULA(synmatrix8[i][2], frame->sb_sample[blk][ch][2],
+ MULA(synmatrix8[i][3], frame->sb_sample[blk][ch][3],
+ MULA(synmatrix8[i][4], frame->sb_sample[blk][ch][4],
+ MULA(synmatrix8[i][5], frame->sb_sample[blk][ch][5],
+ MULA(synmatrix8[i][6], frame->sb_sample[blk][ch][6],
+ MUL( synmatrix8[i][7], frame->sb_sample[blk][ch][7])))))))));
+ }
+
+ /* Compute the samples */
+ for (idx = 0, i = 0; i < 8; i++, idx += 5) {
+ k = (i + 8) & 0xf;
+
+ /* Store in output */
+ frame->pcm_sample[ch][blk * 8 + i] = SCALE8_STAGED2( // Q0
+ MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
+ MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
+ MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
+ MULA(state->V[ch][offset[k] + 3], sbc_proto_8_80m1[idx + 1],
+ MULA(state->V[ch][offset[i] + 4], sbc_proto_8_80m0[idx + 2],
+ MULA(state->V[ch][offset[k] + 5], sbc_proto_8_80m1[idx + 2],
+ MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
+ MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
+ MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
+ MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4])))))))))));
+ }
+}
+
+static int sbc_synthesize_audio(struct sbc_decoder_state *state,
+ struct sbc_frame *frame)
+{
+ int ch, blk;
+
+ switch (frame->subbands) {
+ case 4:
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_synthesize_four(state, frame, ch, blk);
+ }
+ return frame->blocks * 4;
+
+ case 8:
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_synthesize_eight(state, frame, ch, blk);
+ }
+ return frame->blocks * 8;
+
+ default:
+ return -EIO;
+ }
+}
+
+static void sbc_encoder_init(struct sbc_encoder_state *state,
+ const struct sbc_frame *frame)
+{
+ memset(&state->X, 0, sizeof(state->X));
+ state->subbands = frame->subbands;
+ state->position[0] = state->position[1] = 9 * frame->subbands;
+}
+
+static inline void _sbc_analyze_four(const int32_t *in, int32_t *out)
+{
+ sbc_fixed_t t[8], s[5];
+
+ t[0] = SCALE4_STAGE1( /* Q8 */
+ MULA(_sbc_proto_4[0], in[8] - in[32], /* Q18 */
+ MUL( _sbc_proto_4[1], in[16] - in[24])));
+
+ t[1] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[2], in[1],
+ MULA(_sbc_proto_4[3], in[9],
+ MULA(_sbc_proto_4[4], in[17],
+ MULA(_sbc_proto_4[5], in[25],
+ MUL( _sbc_proto_4[6], in[33]))))));
+
+ t[2] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[7], in[2],
+ MULA(_sbc_proto_4[8], in[10],
+ MULA(_sbc_proto_4[9], in[18],
+ MULA(_sbc_proto_4[10], in[26],
+ MUL( _sbc_proto_4[11], in[34]))))));
+
+ t[3] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[12], in[3],
+ MULA(_sbc_proto_4[13], in[11],
+ MULA(_sbc_proto_4[14], in[19],
+ MULA(_sbc_proto_4[15], in[27],
+ MUL( _sbc_proto_4[16], in[35]))))));
+
+ t[4] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[17], in[4] + in[36],
+ MULA(_sbc_proto_4[18], in[12] + in[28],
+ MUL( _sbc_proto_4[19], in[20]))));
+
+ t[5] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[16], in[5],
+ MULA(_sbc_proto_4[15], in[13],
+ MULA(_sbc_proto_4[14], in[21],
+ MULA(_sbc_proto_4[13], in[29],
+ MUL( _sbc_proto_4[12], in[37]))))));
+
+ /* don't compute t[6]... this term always multiplies
+ * with cos(pi/2) = 0 */
+
+ t[7] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[6], in[7],
+ MULA(_sbc_proto_4[5], in[15],
+ MULA(_sbc_proto_4[4], in[23],
+ MULA(_sbc_proto_4[3], in[31],
+ MUL( _sbc_proto_4[2], in[39]))))));
+
+ s[0] = MUL( _anamatrix4[0], t[0] + t[4]);
+ s[1] = MUL( _anamatrix4[2], t[2]);
+ s[2] = MULA(_anamatrix4[1], t[1] + t[3],
+ MUL(_anamatrix4[3], t[5]));
+ s[3] = MULA(_anamatrix4[3], t[1] + t[3],
+ MUL(_anamatrix4[1], -t[5] + t[7]));
+ s[4] = MUL( _anamatrix4[3], t[7]);
+
+ out[0] = SCALE4_STAGE2( s[0] + s[1] + s[2] + s[4]); /* Q0 */
+ out[1] = SCALE4_STAGE2(-s[0] + s[1] + s[3]);
+ out[2] = SCALE4_STAGE2(-s[0] + s[1] - s[3]);
+ out[3] = SCALE4_STAGE2( s[0] + s[1] - s[2] - s[4]);
+}
+
+static inline void sbc_analyze_four(struct sbc_encoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int32_t *x = &state->X[ch][state->position[ch]];
+ int16_t *pcm = &frame->pcm_sample[ch][blk * 4];
+
+ /* Input 4 Audio Samples */
+ x[40] = x[0] = pcm[3];
+ x[41] = x[1] = pcm[2];
+ x[42] = x[2] = pcm[1];
+ x[43] = x[3] = pcm[0];
+
+ _sbc_analyze_four(x, frame->sb_sample_f[blk][ch]);
+
+ state->position[ch] -= 4;
+ if (state->position[ch] < 0)
+ state->position[ch] = 36;
+}
+
+static inline void _sbc_analyze_eight(const int32_t *in, int32_t *out)
+{
+ sbc_fixed_t t[8], s[8];
+
+ t[0] = SCALE8_STAGE1( /* Q10 */
+ MULA(_sbc_proto_8[0], (in[16] - in[64]), /* Q18 = Q18 * Q0 */
+ MULA(_sbc_proto_8[1], (in[32] - in[48]),
+ MULA(_sbc_proto_8[2], in[4],
+ MULA(_sbc_proto_8[3], in[20],
+ MULA(_sbc_proto_8[4], in[36],
+ MUL( _sbc_proto_8[5], in[52])))))));
+
+ t[1] = SCALE8_STAGE1(
+ MULA(_sbc_proto_8[6], in[2],
+ MULA(_sbc_proto_8[7], in[18],
+ MULA(_sbc_proto_8[8], in[34],
+ MULA(_sbc_proto_8[9], in[50],
+ MUL(_sbc_proto_8[10], in[66]))))));
+
+ t[2] = SCALE8_STAGE1(
+ MULA(_sbc_proto_8[11], in[1],
+ MULA(_sbc_proto_8[12], in[17],
+ MULA(_sbc_proto_8[13], in[33],
+ MULA(_sbc_proto_8[14], in[49],
+ MULA(_sbc_proto_8[15], in[65],
+ MULA(_sbc_proto_8[16], in[3],
+ MULA(_sbc_proto_8[17], in[19],
+ MULA(_sbc_proto_8[18], in[35],
+ MULA(_sbc_proto_8[19], in[51],
+ MUL( _sbc_proto_8[20], in[67])))))))))));
+
+ t[3] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[21], in[5],
+ MULA( _sbc_proto_8[22], in[21],
+ MULA( _sbc_proto_8[23], in[37],
+ MULA( _sbc_proto_8[24], in[53],
+ MULA( _sbc_proto_8[25], in[69],
+ MULA(-_sbc_proto_8[15], in[15],
+ MULA(-_sbc_proto_8[14], in[31],
+ MULA(-_sbc_proto_8[13], in[47],
+ MULA(-_sbc_proto_8[12], in[63],
+ MUL( -_sbc_proto_8[11], in[79])))))))))));
+
+ t[4] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[26], in[6],
+ MULA( _sbc_proto_8[27], in[22],
+ MULA( _sbc_proto_8[28], in[38],
+ MULA( _sbc_proto_8[29], in[54],
+ MULA( _sbc_proto_8[30], in[70],
+ MULA(-_sbc_proto_8[10], in[14],
+ MULA(-_sbc_proto_8[9], in[30],
+ MULA(-_sbc_proto_8[8], in[46],
+ MULA(-_sbc_proto_8[7], in[62],
+ MUL( -_sbc_proto_8[6], in[78])))))))))));
+
+ t[5] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[31], in[7],
+ MULA( _sbc_proto_8[32], in[23],
+ MULA( _sbc_proto_8[33], in[39],
+ MULA( _sbc_proto_8[34], in[55],
+ MULA( _sbc_proto_8[35], in[71],
+ MULA(-_sbc_proto_8[20], in[13],
+ MULA(-_sbc_proto_8[19], in[29],
+ MULA(-_sbc_proto_8[18], in[45],
+ MULA(-_sbc_proto_8[17], in[61],
+ MUL( -_sbc_proto_8[16], in[77])))))))))));
+
+ t[6] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[36], (in[8] + in[72]),
+ MULA( _sbc_proto_8[37], (in[24] + in[56]),
+ MULA( _sbc_proto_8[38], in[40],
+ MULA(-_sbc_proto_8[39], in[12],
+ MULA(-_sbc_proto_8[5], in[28],
+ MULA(-_sbc_proto_8[4], in[44],
+ MULA(-_sbc_proto_8[3], in[60],
+ MUL( -_sbc_proto_8[2], in[76])))))))));
+
+ t[7] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[35], in[9],
+ MULA( _sbc_proto_8[34], in[25],
+ MULA( _sbc_proto_8[33], in[41],
+ MULA( _sbc_proto_8[32], in[57],
+ MULA( _sbc_proto_8[31], in[73],
+ MULA(-_sbc_proto_8[25], in[11],
+ MULA(-_sbc_proto_8[24], in[27],
+ MULA(-_sbc_proto_8[23], in[43],
+ MULA(-_sbc_proto_8[22], in[59],
+ MUL( -_sbc_proto_8[21], in[75])))))))))));
+
+ s[0] = MULA( _anamatrix8[0], t[0],
+ MUL( _anamatrix8[1], t[6]));
+ s[1] = MUL( _anamatrix8[7], t[1]);
+ s[2] = MULA( _anamatrix8[2], t[2],
+ MULA( _anamatrix8[3], t[3],
+ MULA( _anamatrix8[4], t[5],
+ MUL( _anamatrix8[5], t[7]))));
+ s[3] = MUL( _anamatrix8[6], t[4]);
+ s[4] = MULA( _anamatrix8[3], t[2],
+ MULA(-_anamatrix8[5], t[3],
+ MULA(-_anamatrix8[2], t[5],
+ MUL( -_anamatrix8[4], t[7]))));
+ s[5] = MULA( _anamatrix8[4], t[2],
+ MULA(-_anamatrix8[2], t[3],
+ MULA( _anamatrix8[5], t[5],
+ MUL( _anamatrix8[3], t[7]))));
+ s[6] = MULA( _anamatrix8[1], t[0],
+ MUL( -_anamatrix8[0], t[6]));
+ s[7] = MULA( _anamatrix8[5], t[2],
+ MULA(-_anamatrix8[4], t[3],
+ MULA( _anamatrix8[3], t[5],
+ MUL( -_anamatrix8[2], t[7]))));
+
+ out[0] = SCALE8_STAGE2( s[0] + s[1] + s[2] + s[3]);
+ out[1] = SCALE8_STAGE2( s[1] - s[3] + s[4] + s[6]);
+ out[2] = SCALE8_STAGE2( s[1] - s[3] + s[5] - s[6]);
+ out[3] = SCALE8_STAGE2(-s[0] + s[1] + s[3] + s[7]);
+ out[4] = SCALE8_STAGE2(-s[0] + s[1] + s[3] - s[7]);
+ out[5] = SCALE8_STAGE2( s[1] - s[3] - s[5] - s[6]);
+ out[6] = SCALE8_STAGE2( s[1] - s[3] - s[4] + s[6]);
+ out[7] = SCALE8_STAGE2( s[0] + s[1] - s[2] + s[3]);
+}
+
+static inline void sbc_analyze_eight(struct sbc_encoder_state *state,
+ struct sbc_frame *frame, int ch,
+ int blk)
+{
+ int32_t *x = &state->X[ch][state->position[ch]];
+ int16_t *pcm = &frame->pcm_sample[ch][blk * 8];
+
+ /* Input 8 Audio Samples */
+ x[80] = x[0] = pcm[7];
+ x[81] = x[1] = pcm[6];
+ x[82] = x[2] = pcm[5];
+ x[83] = x[3] = pcm[4];
+ x[84] = x[4] = pcm[3];
+ x[85] = x[5] = pcm[2];
+ x[86] = x[6] = pcm[1];
+ x[87] = x[7] = pcm[0];
+
+ _sbc_analyze_eight(x, frame->sb_sample_f[blk][ch]);
+
+ state->position[ch] -= 8;
+ if (state->position[ch] < 0)
+ state->position[ch] = 72;
+}
+
+static int sbc_analyze_audio(struct sbc_encoder_state *state,
+ struct sbc_frame *frame)
+{
+ int ch, blk;
+
+ switch (frame->subbands) {
+ case 4:
+ for (ch = 0; ch < frame->channels; ch++)
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_analyze_four(state, frame, ch, blk);
+ return frame->blocks * 4;
+
+ case 8:
+ for (ch = 0; ch < frame->channels; ch++)
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_analyze_eight(state, frame, ch, blk);
+ return frame->blocks * 8;
+
+ default:
+ return -EIO;
+ }
+}
+
+/*
+ * Packs the SBC frame from frame into the memory at data. At most len
+ * bytes will be used, should more memory be needed an appropriate
+ * error code will be returned. Returns the length of the packed frame
+ * on success or a negative value on error.
+ *
+ * The error codes are:
+ * -1 Not enough memory reserved
+ * -2 Unsupported sampling rate
+ * -3 Unsupported number of blocks
+ * -4 Unsupported number of subbands
+ * -5 Bitpool value out of bounds
+ * -99 not implemented
+ */
+
+static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len)
+{
+ int produced;
+ /* Will copy the header parts for CRC-8 calculation here */
+ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int crc_pos = 0;
+
+ uint16_t audio_sample;
+
+ int ch, sb, blk, bit; /* channel, subband, block and bit counters */
+ int bits[2][8]; /* bits distribution */
+ int levels[2][8]; /* levels are derived from that */
+
+ u_int32_t scalefactor[2][8]; /* derived from frame->scale_factor */
+
+ data[0] = SBC_SYNCWORD;
+
+ data[1] = (frame->frequency & 0x03) << 6;
+
+ data[1] |= (frame->block_mode & 0x03) << 4;
+
+ data[1] |= (frame->mode & 0x03) << 2;
+
+ data[1] |= (frame->allocation & 0x01) << 1;
+
+ switch (frame->subbands) {
+ case 4:
+ /* Nothing to do */
+ break;
+ case 8:
+ data[1] |= 0x01;
+ break;
+ default:
+ return -4;
+ break;
+ }
+
+ data[2] = frame->bitpool;
+
+ if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+ frame->bitpool > frame->subbands << 4)
+ return -5;
+
+ if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+ frame->bitpool > frame->subbands << 5)
+ return -5;
+
+ /* Can't fill in crc yet */
+
+ produced = 32;
+
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+ crc_pos = 16;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ frame->scale_factor[ch][sb] = 0;
+ scalefactor[ch][sb] = 2;
+ for (blk = 0; blk < frame->blocks; blk++) {
+ while (scalefactor[ch][sb] < fabs(frame->sb_sample_f[blk][ch][sb])) {
+ frame->scale_factor[ch][sb]++;
+ scalefactor[ch][sb] *= 2;
+ }
+ }
+ }
+ }
+
+ 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 */
+ u_int32_t scalefactor_j[2];
+ uint8_t scale_factor_j[2];
+
+ frame->joint = 0;
+
+ for (sb = 0; sb < frame->subbands - 1; sb++) {
+ scale_factor_j[0] = 0;
+ scalefactor_j[0] = 2;
+ scale_factor_j[1] = 0;
+ scalefactor_j[1] = 2;
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ /* Calculate joint stereo signal */
+ sb_sample_j[blk][0] =
+ (frame->sb_sample_f[blk][0][sb] +
+ frame->sb_sample_f[blk][1][sb]) >> 1;
+ sb_sample_j[blk][1] =
+ (frame->sb_sample_f[blk][0][sb] -
+ frame->sb_sample_f[blk][1][sb]) >> 1;
+
+ /* calculate scale_factor_j and scalefactor_j for joint case */
+ while (scalefactor_j[0] < fabs(sb_sample_j[blk][0])) {
+ scale_factor_j[0]++;
+ scalefactor_j[0] *= 2;
+ }
+ while (scalefactor_j[1] < fabs(sb_sample_j[blk][1])) {
+ scale_factor_j[1]++;
+ scalefactor_j[1] *= 2;
+ }
+ }
+
+ /* decide whether to join this subband */
+ if ((scalefactor[0][sb] + scalefactor[1][sb]) >
+ (scalefactor_j[0] + scalefactor_j[1]) ) {
+ /* use joint stereo for this subband */
+ frame->joint |= 1 << sb;
+ frame->scale_factor[0][sb] = scale_factor_j[0];
+ frame->scale_factor[1][sb] = scale_factor_j[1];
+ scalefactor[0][sb] = scalefactor_j[0];
+ scalefactor[1][sb] = scalefactor_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];
+ }
+ }
+ }
+
+ data[4] = 0;
+ for (sb = 0; sb < frame->subbands - 1; sb++)
+ data[4] |= ((frame->joint >> sb) & 0x01) << (frame->subbands - 1 - sb);
+
+ crc_header[crc_pos >> 3] = data[4];
+
+ produced += frame->subbands;
+ crc_pos += frame->subbands;
+ }
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ data[produced >> 3] <<= 4;
+ crc_header[crc_pos >> 3] <<= 4;
+ data[produced >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
+ crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
+
+ produced += 4;
+ crc_pos += 4;
+ }
+ }
+
+ /* align the last crc byte */
+ if (crc_pos % 8)
+ crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8);
+
+ data[3] = sbc_crc8(crc_header, crc_pos);
+
+ sbc_calculate_bits(frame, bits);
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++)
+ levels[ch][sb] = (1 << bits[ch][sb]) - 1;
+ }
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (levels[ch][sb] > 0) {
+ audio_sample =
+ (uint16_t) ((((frame->sb_sample_f[blk][ch][sb]*levels[ch][sb]) >>
+ (frame->scale_factor[ch][sb] + 1)) +
+ levels[ch][sb]) >> 1);
+ audio_sample <<= 16 - bits[ch][sb];
+ for (bit = 0; bit < bits[ch][sb]; bit++) {
+ data[produced >> 3] <<= 1;
+ if (audio_sample & 0x8000)
+ data[produced >> 3] |= 0x1;
+ audio_sample <<= 1;
+ produced++;
+ }
+ }
+ }
+ }
+ }
+
+ /* align the last byte */
+ if (produced % 8) {
+ data[produced >> 3] <<= 8 - (produced % 8);
+ }
+
+ return (produced + 7) >> 3;
+}
+
+struct sbc_priv {
+ int init;
+ struct sbc_frame frame;
+ struct sbc_decoder_state dec_state;
+ struct sbc_encoder_state enc_state;
+};
+
+static void sbc_set_defaults(sbc_t *sbc, unsigned long flags)
+{
+ sbc->frequency = SBC_FREQ_44100;
+ sbc->mode = SBC_MODE_STEREO;
+ sbc->subbands = SBC_SB_8;
+ sbc->blocks = SBC_BLK_16;
+ sbc->bitpool = 32;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ sbc->endian = SBC_LE;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ sbc->endian = SBC_BE;
+#else
+#error "Unknown byte order"
+#endif
+}
+
+int sbc_init(sbc_t *sbc, unsigned long flags)
+{
+ if (!sbc)
+ return -EIO;
+
+ memset(sbc, 0, sizeof(sbc_t));
+
+ sbc->priv = malloc(sizeof(struct sbc_priv));
+ if (!sbc->priv)
+ return -ENOMEM;
+
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ sbc_set_defaults(sbc, flags);
+
+ return 0;
+}
+
+int sbc_parse(sbc_t *sbc, void *input, int input_len)
+{
+ return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
+}
+
+int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
+{
+ struct sbc_priv *priv;
+ char *ptr;
+ int i, ch, framelen, samples;
+
+ if (!sbc && !input)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ framelen = sbc_unpack_frame(input, &priv->frame, input_len);
+
+ if (!priv->init) {
+ sbc_decoder_init(&priv->dec_state, &priv->frame);
+ priv->init = 1;
+
+ sbc->frequency = priv->frame.frequency;
+ sbc->mode = priv->frame.mode;
+ sbc->subbands = priv->frame.subband_mode;
+ sbc->blocks = priv->frame.block_mode;
+ sbc->allocation = priv->frame.allocation;
+ sbc->bitpool = priv->frame.bitpool;
+
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = sbc_get_frame_length(sbc);
+ }
+
+ if (!output)
+ return framelen;
+
+ if (written)
+ *written = 0;
+
+ samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
+
+ ptr = output;
+
+ if (output_len < samples * priv->frame.channels * 2)
+ samples = output_len / (priv->frame.channels * 2);
+
+ for (i = 0; i < samples; i++) {
+ for (ch = 0; ch < priv->frame.channels; ch++) {
+ int16_t s;
+ s = priv->frame.pcm_sample[ch][i];
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if (sbc->endian == SBC_BE) {
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ if (sbc->endian == SBC_LE) {
+#else
+#error "Unknown byte order"
+#endif
+ *ptr++ = (s & 0xff00) >> 8;
+ *ptr++ = (s & 0x00ff);
+ } else {
+ *ptr++ = (s & 0x00ff);
+ *ptr++ = (s & 0xff00) >> 8;
+ }
+ }
+ }
+
+ if (written)
+ *written = samples * priv->frame.channels * 2;
+
+ return framelen;
+}
+
+int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
+{
+ struct sbc_priv *priv;
+ char *ptr;
+ int i, ch, framelen, samples;
+
+ if (!sbc && !input)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ if (written)
+ *written = 0;
+
+ if (!priv->init) {
+ priv->frame.frequency = sbc->frequency;
+ priv->frame.mode = sbc->mode;
+ priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ priv->frame.allocation = sbc->allocation;
+ priv->frame.subband_mode = sbc->subbands;
+ priv->frame.subbands = sbc->subbands ? 8 : 4;
+ priv->frame.block_mode = sbc->blocks;
+ priv->frame.blocks = 4 + (sbc->blocks * 4);
+ priv->frame.bitpool = sbc->bitpool;
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = sbc_get_frame_length(sbc);
+
+ sbc_encoder_init(&priv->enc_state, &priv->frame);
+ priv->init = 1;
+ }
+
+ /* input must be large enough to encode a complete frame */
+ if (input_len < priv->frame.codesize)
+ return 0;
+
+ /* output must be large enough to receive the encoded frame */
+ if (!output || output_len < priv->frame.length)
+ return -ENOSPC;
+
+ ptr = input;
+
+ for (i = 0; i < priv->frame.subbands * priv->frame.blocks; i++) {
+ for (ch = 0; ch < priv->frame.channels; ch++) {
+ int16_t s;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if (sbc->endian == SBC_BE)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ if (sbc->endian == SBC_LE)
+#else
+#error "Unknown byte order"
+#endif
+ s = (ptr[0] & 0xff) << 8 | (ptr[1] & 0xff);
+ else
+ s = (ptr[0] & 0xff) | (ptr[1] & 0xff) << 8;
+ ptr += 2;
+ priv->frame.pcm_sample[ch][i] = s;
+ }
+ }
+
+ samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
+
+ framelen = sbc_pack_frame(output, &priv->frame, output_len);
+
+ if (written)
+ *written = framelen;
+
+ return samples * priv->frame.channels * 2;
+}
+
+void sbc_finish(sbc_t *sbc)
+{
+ if (!sbc)
+ return;
+
+ if (sbc->priv)
+ free(sbc->priv);
+
+ memset(sbc, 0, sizeof(sbc_t));
+}
+
+int sbc_get_frame_length(sbc_t *sbc)
+{
+ int ret;
+ uint8_t subbands, channels, blocks, joint;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ blocks = 4 + (sbc->blocks * 4);
+ channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ channels = priv->frame.channels;
+ joint = priv->frame.joint;
+ }
+
+ ret = 4 + (4 * subbands * channels) / 8;
+
+ /* This term is not always evenly divide so we round it up */
+ if (channels == 1)
+ ret += ((blocks * channels * sbc->bitpool) + 7) / 8;
+ else
+ ret += (((joint ? subbands : 0) + blocks * sbc->bitpool) + 7)
+ / 8;
+
+ return ret;
+}
+
+int sbc_get_frame_duration(sbc_t *sbc)
+{
+ uint8_t subbands, blocks;
+ uint16_t frequency;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ blocks = 4 + (sbc->blocks * 4);
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ }
+
+ switch (sbc->frequency) {
+ case SBC_FREQ_16000:
+ frequency = 16000;
+ break;
+
+ case SBC_FREQ_32000:
+ frequency = 32000;
+ break;
+
+ case SBC_FREQ_44100:
+ frequency = 44100;
+ break;
+
+ case SBC_FREQ_48000:
+ frequency = 48000;
+ break;
+ default:
+ return 0;
+ }
+
+ return (1000000 * blocks * subbands) / frequency;
+}
+
+int sbc_get_codesize(sbc_t *sbc)
+{
+ uint8_t subbands, channels, blocks;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ blocks = 4 + (sbc->blocks * 4);
+ channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ channels = priv->frame.channels;
+ }
+
+ return subbands * blocks * channels * 2;
+}
+
+int sbc_reinit(sbc_t *sbc, unsigned long flags)
+{
+ struct sbc_priv *priv;
+
+ if (!sbc || !sbc->priv)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ if (priv->init == 1)
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ sbc_set_defaults(sbc, flags);
+
+ return 0;
+}
diff --git a/utils/sbc/sbc.h b/utils/sbc/sbc.h
new file mode 100644
index 00000000..ab47e329
--- /dev/null
+++ b/utils/sbc/sbc.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_H
+#define __SBC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/* sampling frequency */
+#define SBC_FREQ_16000 0x00
+#define SBC_FREQ_32000 0x01
+#define SBC_FREQ_44100 0x02
+#define SBC_FREQ_48000 0x03
+
+/* blocks */
+#define SBC_BLK_4 0x00
+#define SBC_BLK_8 0x01
+#define SBC_BLK_12 0x02
+#define SBC_BLK_16 0x03
+
+/* channel mode */
+#define SBC_MODE_MONO 0x00
+#define SBC_MODE_DUAL_CHANNEL 0x01
+#define SBC_MODE_STEREO 0x02
+#define SBC_MODE_JOINT_STEREO 0x03
+
+/* allocation method */
+#define SBC_AM_LOUDNESS 0x00
+#define SBC_AM_SNR 0x01
+
+/* subbands */
+#define SBC_SB_4 0x00
+#define SBC_SB_8 0x01
+
+/* Data endianess */
+#define SBC_LE 0x00
+#define SBC_BE 0x01
+
+struct sbc_struct {
+ unsigned long flags;
+
+ uint8_t frequency;
+ uint8_t blocks;
+ uint8_t subbands;
+ uint8_t mode;
+ uint8_t allocation;
+ uint8_t bitpool;
+ uint8_t endian;
+
+ void *priv;
+};
+
+typedef struct sbc_struct sbc_t;
+
+int sbc_init(sbc_t *sbc, unsigned long flags);
+int sbc_reinit(sbc_t *sbc, unsigned long flags);
+int sbc_parse(sbc_t *sbc, void *input, int input_len);
+int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *len);
+int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written);
+int sbc_get_frame_length(sbc_t *sbc);
+int sbc_get_frame_duration(sbc_t *sbc);
+int sbc_get_codesize(sbc_t *sbc);
+void sbc_finish(sbc_t *sbc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SBC_H */
diff --git a/utils/sbc/sbc_math.h b/utils/sbc/sbc_math.h
new file mode 100644
index 00000000..b3d87a62
--- /dev/null
+++ b/utils/sbc/sbc_math.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define fabs(x) ((x) < 0 ? -(x) : (x))
+/* C does not provide an explicit arithmetic shift right but this will
+ always be correct and every compiler *should* generate optimal code */
+#define ASR(val, bits) ((-2 >> 1 == -1) ? \
+ ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
+
+#define SCALE_PROTO4_TBL 15
+#define SCALE_ANA4_TBL 17
+#define SCALE_PROTO8_TBL 16
+#define SCALE_ANA8_TBL 17
+#define SCALE_SPROTO4_TBL 12
+#define SCALE_SPROTO8_TBL 14
+#define SCALE_NPROTO4_TBL 11
+#define SCALE_NPROTO8_TBL 11
+#define SCALE4_STAGE1_BITS 15
+#define SCALE4_STAGE2_BITS 16
+#define SCALE4_STAGED1_BITS 15
+#define SCALE4_STAGED2_BITS 16
+#define SCALE8_STAGE1_BITS 15
+#define SCALE8_STAGE2_BITS 15
+#define SCALE8_STAGED1_BITS 15
+#define SCALE8_STAGED2_BITS 16
+
+typedef int32_t sbc_fixed_t;
+
+#define SCALE4_STAGE1(src) ASR(src, SCALE4_STAGE1_BITS)
+#define SCALE4_STAGE2(src) ASR(src, SCALE4_STAGE2_BITS)
+#define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS)
+#define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS)
+#define SCALE8_STAGE1(src) ASR(src, SCALE8_STAGE1_BITS)
+#define SCALE8_STAGE2(src) ASR(src, SCALE8_STAGE2_BITS)
+#define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS)
+#define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS)
+
+#define SBC_FIXED_0(val) { val = 0; }
+#define MUL(a, b) ((a) * (b))
+#ifdef __arm__
+#define MULA(a, b, res) ({ \
+ int tmp = res; \
+ __asm__( \
+ "mla %0, %2, %3, %0" \
+ : "=&r" (tmp) \
+ : "0" (tmp), "r" (a), "r" (b)); \
+ tmp; })
+#else
+#define MULA(a, b, res) ((a) * (b) + (res))
+#endif
diff --git a/utils/sbc/sbc_tables.h b/utils/sbc/sbc_tables.h
new file mode 100644
index 00000000..7ac4e68b
--- /dev/null
+++ b/utils/sbc/sbc_tables.h
@@ -0,0 +1,167 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset4[4][4] = {
+ { -1, 0, 0, 0 },
+ { -2, 0, 0, 1 },
+ { -2, 0, 0, 1 },
+ { -2, 0, 0, 1 }
+};
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset8[4][8] = {
+ { -2, 0, 0, 0, 0, 0, 0, 1 },
+ { -3, 0, 0, 0, 0, 0, 1, 2 },
+ { -4, 0, 0, 0, 0, 0, 1, 2 },
+ { -4, 0, 0, 0, 0, 0, 1, 2 }
+};
+
+#define SP4(val) ASR(val, SCALE_PROTO4_TBL)
+#define SA4(val) ASR(val, SCALE_ANA4_TBL)
+#define SP8(val) ASR(val, SCALE_PROTO8_TBL)
+#define SA8(val) ASR(val, SCALE_ANA8_TBL)
+#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
+#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
+#define SN4(val) ASR(val, SCALE_NPROTO4_TBL)
+#define SN8(val) ASR(val, SCALE_NPROTO8_TBL)
+
+static const int32_t _sbc_proto_4[20] = {
+ SP4(0x02cb3e8c), SP4(0x22b63dc0), SP4(0x002329cc), SP4(0x053b7548),
+ SP4(0x31eab940), SP4(0xec1f5e60), SP4(0xff3773a8), SP4(0x0061c5a7),
+ SP4(0x07646680), SP4(0x3f239480), SP4(0xf89f23a8), SP4(0x007a4737),
+ SP4(0x00b32807), SP4(0x083ddc80), SP4(0x4825e480), SP4(0x0191e578),
+ SP4(0x00ff11ca), SP4(0x00fb7991), SP4(0x069fdc58), SP4(0x4b584000)
+};
+
+static const int32_t _anamatrix4[4] = {
+ SA4(0x2d413cc0), SA4(0x3b20d780), SA4(0x40000000), SA4(0x187de2a0)
+};
+
+static const int32_t _sbc_proto_8[40] = {
+ SP8(0x02e5cd20), SP8(0x22d0c200), SP8(0x006bfe27), SP8(0x07808930),
+ SP8(0x3f1c8800), SP8(0xf8810d70), SP8(0x002cfdc6), SP8(0x055acf28),
+ SP8(0x31f566c0), SP8(0xebfe57e0), SP8(0xff27c437), SP8(0x001485cc),
+ SP8(0x041c6e58), SP8(0x2a7cfa80), SP8(0xe4c4a240), SP8(0xfe359e4c),
+ SP8(0x0048b1f8), SP8(0x0686ce30), SP8(0x38eec5c0), SP8(0xf2a1b9f0),
+ SP8(0xffe8904a), SP8(0x0095698a), SP8(0x0824a480), SP8(0x443b3c00),
+ SP8(0xfd7badc8), SP8(0x00d3e2d9), SP8(0x00c183d2), SP8(0x084e1950),
+ SP8(0x4810d800), SP8(0x017f43fe), SP8(0x01056dd8), SP8(0x00e9cb9f),
+ SP8(0x07d7d090), SP8(0x4a708980), SP8(0x0488fae8), SP8(0x0113bd20),
+ SP8(0x0107b1a8), SP8(0x069fb3c0), SP8(0x4b3db200), SP8(0x00763f48)
+};
+
+static const int32_t sbc_proto_4_40m0[] = {
+ SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
+ SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8),
+ SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330),
+ SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00),
+ SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7)
+};
+
+static const int32_t sbc_proto_4_40m1[] = {
+ SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475),
+ SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370),
+ SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b),
+ SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b),
+ SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7)
+};
+
+static const int32_t sbc_proto_8_80m0[] = {
+ SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100),
+ SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0),
+ SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c),
+ SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705),
+ SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db),
+ SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948),
+ SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200),
+ SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358),
+ SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31),
+ SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170)
+};
+
+static const int32_t sbc_proto_8_80m1[] = {
+ SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620),
+ SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40),
+ SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01),
+ SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94),
+ SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b),
+ SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68),
+ SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20),
+ SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410),
+ SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da),
+ SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a)
+};
+
+static const int32_t _anamatrix8[8] = {
+ SA8(0x3b20d780), SA8(0x187de2a0), SA8(0x3ec52f80), SA8(0x3536cc40),
+ SA8(0x238e7680), SA8(0x0c7c5c20), SA8(0x2d413cc0), SA8(0x40000000)
+};
+
+static const int32_t synmatrix4[8][4] = {
+ { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) },
+ { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) },
+ { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) },
+ { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) },
+ { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) },
+ { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) },
+ { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) },
+ { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }
+};
+
+static const int32_t synmatrix8[16][8] = {
+ { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798),
+ SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) },
+ { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988),
+ SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) },
+ { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac),
+ SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) },
+ { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10),
+ SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) },
+ { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000),
+ SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) },
+ { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0),
+ SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) },
+ { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54),
+ SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) },
+ { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678),
+ SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) },
+ { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868),
+ SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) },
+ { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+ SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) },
+ { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+ SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+ { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+ SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+ { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000),
+ SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) },
+ { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+ SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+ { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+ SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+ { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+ SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
+};
diff --git a/utils/sbc/sbcdec.c b/utils/sbc/sbcdec.c
new file mode 100644
index 00000000..5ac02b44
--- /dev/null
+++ b/utils/sbc/sbcdec.c
@@ -0,0 +1,267 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) decoder
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+
+#include "sbc.h"
+
+#define BUF_SIZE 8192
+
+static void decode(char *filename, char *output, int tofile)
+{
+ unsigned char buf[BUF_SIZE], *stream;
+ struct stat st;
+ off_t filesize;
+ sbc_t sbc;
+ int fd, ad, pos, streamlen, framelen, count, written, len;
+ int format = AFMT_S16_BE, frequency, channels;
+
+ if (stat(filename, &st) < 0) {
+ fprintf(stderr, "Can't get size of file %s: %s\n",
+ filename, strerror(errno));
+ return;
+ }
+
+ filesize = st.st_size;
+ stream = malloc(st.st_size);
+
+ if (!stream) {
+ fprintf(stderr, "Can't allocate memory for %s: %s\n",
+ filename, strerror(errno));
+ return;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open file %s: %s\n",
+ filename, strerror(errno));
+ goto free;
+ }
+
+ if (read(fd, stream, st.st_size) != st.st_size) {
+ fprintf(stderr, "Can't read content of %s: %s\n",
+ filename, strerror(errno));
+ close(fd);
+ goto free;
+ }
+
+ close(fd);
+
+ pos = 0;
+ streamlen = st.st_size;
+
+ if (tofile)
+ ad = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ else
+ ad = open(output, O_WRONLY, 0);
+
+ if (ad < 0) {
+ fprintf(stderr, "Can't open output %s: %s\n",
+ output, strerror(errno));
+ goto free;
+ }
+
+ sbc_init(&sbc, 0L);
+ sbc.endian = SBC_BE;
+
+ framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len);
+ channels = sbc.mode == SBC_MODE_MONO ? 1 : 2;
+ switch (sbc.frequency) {
+ case SBC_FREQ_16000:
+ frequency = 16000;
+ break;
+
+ case SBC_FREQ_32000:
+ frequency = 32000;
+ break;
+
+ case SBC_FREQ_44100:
+ frequency = 44100;
+ break;
+
+ case SBC_FREQ_48000:
+ frequency = 48000;
+ break;
+ default:
+ frequency = 0;
+ }
+
+ printf("%d Hz, %d channels\n", frequency, channels);
+ if (!tofile) {
+ if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) {
+ fprintf(stderr, "Can't set audio format on %s: %s\n",
+ output, strerror(errno));
+ goto close;
+ }
+ if (ioctl(ad, SNDCTL_DSP_CHANNELS, &channels) < 0) {
+ fprintf(stderr,
+ "Can't set number of channels on %s: %s\n",
+ output, strerror(errno));
+ goto close;
+ }
+
+ if (ioctl(ad, SNDCTL_DSP_SPEED, &frequency) < 0) {
+ fprintf(stderr, "Can't set audio rate on %s: %s\n",
+ output, strerror(errno));
+ goto close;
+ }
+ }
+
+ count = 0;
+ while (framelen > 0) {
+ /* we have completed an sbc_decode at this point sbc.len is the
+ * length of the frame we just decoded count is the number of
+ * decoded bytes yet to be written */
+
+ if (count + len >= BUF_SIZE) {
+ /* buffer is too full to stuff decoded audio in so it
+ * must be written to the device */
+ written = write(ad, buf, count);
+ if (written > 0)
+ count -= written;
+ }
+
+ /* sanity check */
+ if (count + len >= BUF_SIZE) {
+ fprintf(stderr,
+ "buffer size of %d is too small for decoded"
+ " data (%d)\n", BUF_SIZE, len + count);
+ exit(1);
+ }
+
+ /* increase the count */
+ count += len;
+
+ /* push the pointer in the file forward to the next bit to be
+ * decoded tell the decoder to decode up to the remaining
+ * length of the file (!) */
+ pos += framelen;
+ framelen = sbc_decode(&sbc, stream + pos, streamlen - pos,
+ buf + count, sizeof(buf) - count,
+ &len);
+ }
+
+ if (count > 0) {
+ written = write(ad, buf, count);
+ if (written > 0)
+ count -= written;
+ }
+
+close:
+ sbc_finish(&sbc);
+
+ close(ad);
+
+free:
+ free(stream);
+}
+
+static void usage(void)
+{
+ printf("SBC decoder utility ver %s\n", VERSION);
+ printf("Copyright (c) 2004-2008 Marcel Holtmann\n\n");
+
+ printf("Usage:\n"
+ "\tsbcdec [options] file(s)\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-h, --help Display help\n"
+ "\t-v, --verbose Verbose mode\n"
+ "\t-d, --device <dsp> Sound device\n"
+ "\t-f, --file <file> Decode to a file\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device", 1, 0, 'd' },
+ { "verbose", 0, 0, 'v' },
+ { "file", 1, 0, 'f' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ char *output = NULL;
+ int i, opt, verbose = 0, tofile = 0;
+
+ while ((opt = getopt_long(argc, argv, "+hvd:f:", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'h':
+ usage();
+ exit(0);
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'd':
+ if (output)
+ free(output);
+ output = strdup(optarg);
+ tofile = 0;
+ break;
+
+ case 'f' :
+ if (output)
+ free(output);
+ output = strdup(optarg);
+ tofile = 1;
+ break;
+
+ default:
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ for (i = 0; i < argc; i++)
+ decode(argv[i], output ? output : "/dev/dsp", tofile);
+
+ if (output)
+ free(output);
+
+ return 0;
+}
diff --git a/utils/sbc/sbcenc.c b/utils/sbc/sbcenc.c
new file mode 100644
index 00000000..e17f8fdb
--- /dev/null
+++ b/utils/sbc/sbcenc.c
@@ -0,0 +1,280 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) encoder
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+
+#include "sbc.h"
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
+#define LE_SHORT(v) (v)
+#define LE_INT(v) (v)
+#define BE_SHORT(v) bswap_16(v)
+#define BE_INT(v) bswap_32(v)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
+#define LE_SHORT(v) bswap_16(v)
+#define LE_INT(v) bswap_32(v)
+#define BE_SHORT(v) (v)
+#define BE_INT(v) (v)
+#else
+#error "Wrong endian"
+#endif
+
+#define AU_MAGIC COMPOSE_ID('.','s','n','d')
+
+#define AU_FMT_ULAW 1
+#define AU_FMT_LIN8 2
+#define AU_FMT_LIN16 3
+
+struct au_header {
+ uint32_t magic; /* '.snd' */
+ uint32_t hdr_size; /* size of header (min 24) */
+ uint32_t data_size; /* size of data */
+ uint32_t encoding; /* see to AU_FMT_XXXX */
+ uint32_t sample_rate; /* sample rate */
+ uint32_t channels; /* number of channels (voices) */
+};
+
+static ssize_t __read(int fd, void *buf, size_t count)
+{
+ ssize_t len, pos = 0;
+
+ while (count > 0) {
+ len = read(fd, buf + pos, count);
+ if (len <= 0)
+ return len;
+
+ count -= len;
+ pos += len;
+ }
+
+ return pos;
+}
+
+static ssize_t __write(int fd, const void *buf, size_t count)
+{
+ ssize_t len, pos = 0;
+
+ while (count > 0) {
+ len = write(fd, buf + pos, count);
+ if (len <= 0)
+ return len;
+
+ count -= len;
+ pos += len;
+ }
+
+ return pos;
+}
+
+static void encode(char *filename, int subbands, int joint)
+{
+ struct au_header *au_hdr;
+ unsigned char input[2048], output[2048];
+ sbc_t sbc;
+ int fd, len, size, count, encoded;
+
+ if (strcmp(filename, "-")) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open file %s: %s\n",
+ filename, strerror(errno));
+ return;
+ }
+ } else
+ fd = fileno(stdin);
+
+ len = __read(fd, input, sizeof(input));
+ if (len < sizeof(*au_hdr)) {
+ if (fd > fileno(stderr))
+ fprintf(stderr, "Can't read header from file %s: %s\n",
+ filename, strerror(errno));
+ else
+ perror("Can't read audio header");
+ goto done;
+ }
+
+ au_hdr = (struct au_header *) input;
+
+ if (au_hdr->magic != AU_MAGIC ||
+ BE_INT(au_hdr->hdr_size) > 128 ||
+ BE_INT(au_hdr->hdr_size) < 24 ||
+ BE_INT(au_hdr->encoding) != AU_FMT_LIN16) {
+ fprintf(stderr, "Data is not in Sun/NeXT audio S16_BE format\n");
+ goto done;
+ }
+
+ sbc_init(&sbc, 0L);
+
+ switch (BE_INT(au_hdr->sample_rate)) {
+ case 16000:
+ sbc.frequency = SBC_FREQ_16000;
+ break;
+ case 32000:
+ sbc.frequency = SBC_FREQ_32000;
+ break;
+ case 44100:
+ sbc.frequency = SBC_FREQ_44100;
+ break;
+ case 48000:
+ sbc.frequency = SBC_FREQ_48000;
+ break;
+ }
+
+ sbc.subbands = subbands == 4 ? SBC_SB_4 : SBC_SB_8;
+
+ if (BE_INT(au_hdr->channels) == 1)
+ sbc.mode = SBC_MODE_MONO;
+ else if (joint)
+ sbc.mode = SBC_MODE_JOINT_STEREO;
+ else
+ sbc.mode = SBC_MODE_STEREO;
+
+ sbc.endian = SBC_BE;
+ count = BE_INT(au_hdr->data_size);
+ size = len - BE_INT(au_hdr->hdr_size);
+ memmove(input, input + BE_INT(au_hdr->hdr_size), size);
+
+ while (1) {
+ if (size < sizeof(input)) {
+ len = __read(fd, input + size, sizeof(input) - size);
+ if (len == 0)
+ break;
+
+ if (len < 0) {
+ perror("Can't read audio data");
+ break;
+ }
+
+ size += len;
+ }
+
+ len = sbc_encode(&sbc, input, size, output, sizeof(output),
+ &encoded);
+ if (len < size)
+ memmove(input, input + len, size - len);
+
+ size -= len;
+
+ len = __write(fileno(stdout), output, encoded);
+ if (len == 0)
+ break;
+
+ if (len < 0 || len != encoded) {
+ perror("Can't write SBC output");
+ break;
+ }
+ }
+
+ sbc_finish(&sbc);
+
+done:
+ if (fd > fileno(stderr))
+ close(fd);
+}
+
+static void usage(void)
+{
+ printf("SBC encoder utility ver %s\n", VERSION);
+ printf("Copyright (c) 2004-2008 Marcel Holtmann\n\n");
+
+ printf("Usage:\n"
+ "\tsbcenc [options] file(s)\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-h, --help Display help\n"
+ "\t-v, --verbose Verbose mode\n"
+ "\t-s, --subbands Number of subbands to use (4 or 8)\n"
+ "\t-j, --joint Joint stereo\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "verbose", 0, 0, 'v' },
+ { "subbands", 1, 0, 's' },
+ { "joint", 0, 0, 'j' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ int i, opt, verbose = 0, subbands = 8, joint = 0;
+
+ while ((opt = getopt_long(argc, argv, "+hvs:j", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'h':
+ usage();
+ exit(0);
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 's':
+ subbands = atoi(strdup(optarg));
+ if (subbands != 8 && subbands != 4) {
+ fprintf(stderr, "Invalid subbands %d!\n",
+ subbands);
+ exit(1);
+ }
+ break;
+
+ case 'j':
+ joint = 1;
+ break;
+
+ default:
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ for (i = 0; i < argc; i++)
+ encode(argv[i], subbands, joint);
+
+ return 0;
+}
diff --git a/utils/sbc/sbcinfo.c b/utils/sbc/sbcinfo.c
new file mode 100644
index 00000000..c1f0631a
--- /dev/null
+++ b/utils/sbc/sbcinfo.c
@@ -0,0 +1,319 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgen.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+struct sbc_frame_hdr {
+ uint8_t syncword:8; /* Sync word */
+ uint8_t subbands:1; /* Subbands */
+ uint8_t allocation_method:1; /* Allocation method */
+ uint8_t channel_mode:2; /* Channel mode */
+ uint8_t blocks:2; /* Blocks */
+ uint8_t sampling_frequency:2; /* Sampling frequency */
+ uint8_t bitpool:8; /* Bitpool */
+ uint8_t crc_check:8; /* CRC check */
+} __attribute__ ((packed));
+#elif __BYTE_ORDER == __BIG_ENDIAN
+struct sbc_frame_hdr {
+ uint8_t syncword:8; /* Sync word */
+ uint8_t sampling_frequency:2; /* Sampling frequency */
+ uint8_t blocks:2; /* Blocks */
+ uint8_t channel_mode:2; /* Channel mode */
+ uint8_t allocation_method:1; /* Allocation method */
+ uint8_t subbands:1; /* Subbands */
+ uint8_t bitpool:8; /* Bitpool */
+ uint8_t crc_check:8; /* CRC check */
+} __attribute__ ((packed));
+#else
+#error "Unknown byte order"
+#endif
+
+static int calc_frame_len(struct sbc_frame_hdr *hdr)
+{
+ int tmp, nrof_subbands, nrof_blocks;
+
+ nrof_subbands = (hdr->subbands + 1) * 4;
+ nrof_blocks = (hdr->blocks + 1) * 4;
+
+ switch (hdr->channel_mode) {
+ case 0x00:
+ nrof_subbands /= 2;
+ tmp = nrof_blocks * hdr->bitpool;
+ break;
+ case 0x01:
+ tmp = nrof_blocks * hdr->bitpool * 2;
+ break;
+ case 0x02:
+ tmp = nrof_blocks * hdr->bitpool;
+ break;
+ case 0x03:
+ tmp = nrof_blocks * hdr->bitpool + nrof_subbands;
+ break;
+ default:
+ return 0;
+ }
+
+ return (nrof_subbands + ((tmp + 7) / 8));
+}
+
+static double calc_bit_rate(struct sbc_frame_hdr *hdr)
+{
+ int nrof_subbands, nrof_blocks;
+ double f;
+
+ nrof_subbands = (hdr->subbands + 1) * 4;
+ nrof_blocks = (hdr->blocks + 1) * 4;
+
+ switch (hdr->sampling_frequency) {
+ case 0:
+ f = 16;
+ break;
+ case 1:
+ f = 32;
+ break;
+ case 2:
+ f = 44.1;
+ break;
+ case 3:
+ f = 48;
+ break;
+ default:
+ return 0;
+ }
+
+ return ((8 * (calc_frame_len(hdr) + 4) * f) /
+ (nrof_subbands * nrof_blocks));
+}
+
+static char *freq2str(uint8_t freq)
+{
+ switch (freq) {
+ case 0:
+ return "16 kHz";
+ case 1:
+ return "32 kHz";
+ case 2:
+ return "44.1 kHz";
+ case 3:
+ return "48 kHz";
+ default:
+ return "Unknown";
+ }
+}
+
+static char *mode2str(uint8_t mode)
+{
+ switch (mode) {
+ case 0:
+ return "Mono";
+ case 1:
+ return "Dual Channel";
+ case 2:
+ return "Stereo";
+ case 3:
+ return "Joint Stereo";
+ default:
+ return "Unknown";
+ }
+}
+
+static ssize_t __read(int fd, void *buf, size_t count)
+{
+ ssize_t len, pos = 0;
+
+ while (count > 0) {
+ len = read(fd, buf + pos, count);
+ if (len <= 0)
+ return len;
+
+ count -= len;
+ pos += len;
+ }
+
+ return pos;
+}
+
+#define SIZE 32
+
+static int analyze_file(char *filename)
+{
+ struct sbc_frame_hdr hdr;
+ unsigned char buf[64];
+ double rate;
+ int bitpool[SIZE], frame_len[SIZE];
+ int subbands, blocks, freq, mode, method;
+ int n, p1, p2, fd, len, size, count, num;
+
+ if (strcmp(filename, "-")) {
+ printf("Filename\t\t%s\n", basename(filename));
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror("Can't open file");
+ return -1;
+ }
+ } else
+ fd = fileno(stdin);
+
+ len = __read(fd, &hdr, sizeof(hdr));
+ if (len != sizeof(hdr) || hdr.syncword != 0x9c) {
+ fprintf(stderr, "Not a SBC audio file\n");
+ return -1;
+ }
+
+ subbands = (hdr.subbands + 1) * 4;
+ blocks = (hdr.blocks + 1) * 4;
+ freq = hdr.sampling_frequency;
+ mode = hdr.channel_mode;
+ method = hdr.allocation_method;
+
+ count = calc_frame_len(&hdr);
+
+ bitpool[0] = hdr.bitpool;
+ frame_len[0] = count + 4;
+
+ for (n = 1; n < SIZE; n++) {
+ bitpool[n] = 0;
+ frame_len[n] = 0;
+ }
+
+ if (lseek(fd, 0, SEEK_SET) < 0) {
+ num = 1;
+ rate = calc_bit_rate(&hdr);
+ while (count) {
+ size = count > sizeof(buf) ? sizeof(buf) : count;
+ len = __read(fd, buf, size);
+ if (len < 0)
+ break;
+ count -= len;
+ }
+ } else {
+ num = 0;
+ rate = 0;
+ }
+
+ while (1) {
+ len = __read(fd, &hdr, sizeof(hdr));
+ if (len < 0) {
+ fprintf(stderr, "Unable to read frame header"
+ " (error %d)\n", errno);
+ break;
+ }
+
+ if (len == 0)
+ break;
+
+ if (len < sizeof(hdr) || hdr.syncword != 0x9c) {
+ fprintf(stderr, "Corrupted SBC stream "
+ "(len %d syncword 0x%02x)\n",
+ len, hdr.syncword);
+ break;
+ }
+
+ count = calc_frame_len(&hdr);
+ len = count + 4;
+
+ p1 = -1;
+ p2 = -1;
+ for (n = 0; n < SIZE; n++) {
+ if (p1 < 0 && (bitpool[n] == 0 || bitpool[n] == hdr.bitpool))
+ p1 = n;
+ if (p2 < 0 && (frame_len[n] == 0 || frame_len[n] == len))
+ p2 = n;
+ }
+ if (p1 >= 0)
+ bitpool[p1] = hdr.bitpool;
+ if (p2 >= 0)
+ frame_len[p2] = len;
+
+ while (count) {
+ size = count > sizeof(buf) ? sizeof(buf) : count;
+
+ len = __read(fd, buf, size);
+ if (len != size) {
+ fprintf(stderr, "Unable to read frame data "
+ "(error %d)\n", errno);
+ break;
+ }
+
+ count -= len;
+ }
+
+ rate += calc_bit_rate(&hdr);
+ num++;
+ }
+
+ printf("Subbands\t\t%d\n", subbands);
+ printf("Block length\t\t%d\n", blocks);
+ printf("Sampling frequency\t%s\n", freq2str(freq));
+ printf("Channel mode\t\t%s\n", mode2str(hdr.channel_mode));
+ printf("Allocation method\t%s\n", method ? "SNR" : "Loudness");
+ printf("Bitpool\t\t\t%d", bitpool[0]);
+ for (n = 1; n < SIZE; n++)
+ if (bitpool[n] > 0)
+ printf(", %d", bitpool[n]);
+ printf("\n");
+ printf("Number of frames\t%d\n", num);
+ printf("Frame length\t\t%d", frame_len[0]);
+ for (n = 1; n < SIZE; n++)
+ if (frame_len[n] > 0)
+ printf(", %d", frame_len[n]);
+ printf(" Bytes\n");
+ if (num > 0)
+ printf("Bit rate\t\t%.3f kbps\n", rate / num);
+
+ if (fd > fileno(stderr))
+ close(fd);
+
+ printf("\n");
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: sbcinfo <file>\n");
+ exit(1);
+ }
+
+ for (i = 0; i < argc - 1; i++)
+ if (analyze_file(argv[i + 1]) < 0)
+ exit(1);
+
+ return 0;
+}
diff --git a/utils/sbc/sbctester.c b/utils/sbc/sbctester.c
new file mode 100644
index 00000000..260f34ae
--- /dev/null
+++ b/utils/sbc/sbctester.c
@@ -0,0 +1,357 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2007-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2007-2008 Frederic Dalleau <fdalleau@free.fr>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sndfile.h>
+#include <math.h>
+#include <string.h>
+
+#define MAXCHANNELS 2
+#define DEFACCURACY 7
+
+static double sampletobits(short sample16, int verbose)
+{
+ double bits = 0;
+ unsigned short bit;
+ int i;
+
+ if (verbose)
+ printf("===> sampletobits(%hd, %04hX)\n", sample16, sample16);
+
+ /* Bit 0 is MSB */
+ if (sample16 < 0)
+ bits = -1;
+
+ if (verbose)
+ printf("%d", (sample16 < 0) ? 1 : 0);
+
+ /* Bit 15 is LSB */
+ for (i = 1; i < 16; i++) {
+ bit = (unsigned short) sample16;
+ bit >>= 15 - i;
+ bit %= 2;
+
+ if (verbose)
+ printf("%d", bit);
+
+ if (bit)
+ bits += (1.0 / pow(2.0, i));
+ }
+
+ if (verbose)
+ printf("\n");
+
+ return bits;
+}
+
+static int calculate_rms_level(SNDFILE * sndref, SF_INFO * infosref,
+ SNDFILE * sndtst, SF_INFO * infostst,
+ int accuracy, char *csvname)
+{
+ short refsample[MAXCHANNELS], tstsample[MAXCHANNELS];
+ double refbits, tstbits;
+ double rms_accu[MAXCHANNELS];
+ double rms_level[MAXCHANNELS];
+ double rms_limit = 1.0 / (pow(2.0, accuracy - 1) * pow(12.0, 0.5));
+ FILE *csv = NULL;
+ int i, j, r1, r2, verdict;
+
+ if (csvname)
+ csv = fopen(csvname, "wt");
+
+ if (csv) {
+ fprintf(csv, "num;");
+ for (j = 0; j < infostst->channels; j++)
+ fprintf(csv, "ref channel %d;tst channel %d;", j, j);
+ fprintf(csv, "\r\n");
+ }
+
+ sf_seek(sndref, 0, SEEK_SET);
+ sf_seek(sndtst, 0, SEEK_SET);
+
+ memset(rms_accu, 0, sizeof(rms_accu));
+ memset(rms_level, 0, sizeof(rms_level));
+
+ for (i = 0; i < infostst->frames; i++) {
+ if (csv)
+ fprintf(csv, "%d;", i);
+
+ r1 = sf_read_short(sndref, refsample, infostst->channels);
+ if (r1 != infostst->channels) {
+ printf("Failed to read reference data: %s "
+ "(r1=%d, channels=%d)",
+ sf_strerror(sndref), r1,
+ infostst->channels);
+ if (csv)
+ fclose(csv);
+ return -1;
+ }
+
+ r2 = sf_read_short(sndtst, tstsample, infostst->channels);
+ if (r2 != infostst->channels) {
+ printf("Failed to read test data: %s "
+ "(r2=%d, channels=%d)\n",
+ sf_strerror(sndtst), r2,
+ infostst->channels);
+ if (csv)
+ fclose(csv);
+ return -1;
+ }
+
+ for (j = 0; j < infostst->channels; j++) {
+ if (csv)
+ fprintf(csv, "%d;%d;", refsample[j],
+ tstsample[j]);
+
+ refbits = sampletobits(refsample[j], 0);
+ tstbits = sampletobits(tstsample[j], 0);
+
+ rms_accu[j] += pow(tstbits - refbits, 2.0);
+ }
+
+ if (csv)
+ fprintf(csv, "\r\n");
+ }
+
+ printf("Limit: %f\n", rms_limit);
+
+ for (j = 0; j < infostst->channels; j++) {
+ printf("Channel %d\n", j);
+ printf("Accumulated %f\n", rms_accu[j]);
+ rms_accu[j] /= (double) infostst->frames;
+ printf("Accumulated / %f = %f\n", (double) infostst->frames,
+ rms_accu[j]);
+ rms_level[j] = sqrt(rms_accu[j]);
+ printf("Level = %f (%f x %f = %f)\n",
+ rms_level[j], rms_level[j], rms_level[j],
+ rms_level[j] * rms_level[j]);
+ }
+
+ verdict = 1;
+
+ for (j = 0; j < infostst->channels; j++) {
+ printf("Channel %d: %f\n", j, rms_level[j]);
+
+ if (rms_level[j] > rms_limit)
+ verdict = 0;
+ }
+
+ printf("%s return %d\n", __FUNCTION__, verdict);
+
+ return verdict;
+}
+
+static int check_absolute_diff(SNDFILE * sndref, SF_INFO * infosref,
+ SNDFILE * sndtst, SF_INFO * infostst,
+ int accuracy)
+{
+ short refsample[MAXCHANNELS], tstsample[MAXCHANNELS];
+ short refmax[MAXCHANNELS], tstmax[MAXCHANNELS];
+ double refbits, tstbits;
+ double rms_absolute = 1.0 / (pow(2, accuracy - 2));
+ double calc_max[MAXCHANNELS];
+ int calc_count = 0;
+ short r1, r2;
+ double cur_diff;
+ int i, j, verdict;
+
+ memset(&refmax, 0, sizeof(refmax));
+ memset(&tstmax, 0, sizeof(tstmax));
+ memset(&calc_max, 0, sizeof(calc_max));
+ memset(&refsample, 0, sizeof(refsample));
+ memset(&tstsample, 0, sizeof(tstsample));
+
+ sf_seek(sndref, 0, SEEK_SET);
+ sf_seek(sndtst, 0, SEEK_SET);
+
+ verdict = 1;
+
+ printf("Absolute max: %f\n", rms_absolute);
+ for (i = 0; i < infostst->frames; i++) {
+ r1 = sf_read_short(sndref, refsample, infostst->channels);
+
+ if (r1 != infostst->channels) {
+ printf("Failed to read reference data: %s "
+ "(r1=%d, channels=%d)",
+ sf_strerror(sndref), r1,
+ infostst->channels);
+ return -1;
+ }
+
+ r2 = sf_read_short(sndtst, tstsample, infostst->channels);
+ if (r2 != infostst->channels) {
+ printf("Failed to read test data: %s "
+ "(r2=%d, channels=%d)\n",
+ sf_strerror(sndtst), r2,
+ infostst->channels);
+ return -1;
+ }
+
+ for (j = 0; j < infostst->channels; j++) {
+ refbits = sampletobits(refsample[j], 0);
+ tstbits = sampletobits(tstsample[j], 0);
+
+ cur_diff = fabs(tstbits - refbits);
+
+ if (cur_diff > rms_absolute) {
+ calc_count++;
+ /* printf("Channel %d exceeded : fabs(%f - %f) = %f > %f\n", j, tstbits, refbits, cur_diff, rms_absolute); */
+ verdict = 0;
+ }
+
+ if (cur_diff > calc_max[j]) {
+ calc_max[j] = cur_diff;
+ refmax[j] = refsample[j];
+ tstmax[j] = tstsample[j];
+ }
+ }
+ }
+
+ for (j = 0; j < infostst->channels; j++) {
+ printf("Calculated max: %f (%hd-%hd=%hd)\n",
+ calc_max[j], tstmax[j], refmax[j],
+ tstmax[j] - refmax[j]);
+ }
+
+ printf("%s return %d\n", __FUNCTION__, verdict);
+
+ return verdict;
+}
+
+static void usage()
+{
+ printf("SBC conformance test ver %s\n", VERSION);
+ printf("Copyright (c) 2007-2008 Marcel Holtmann\n");
+ printf("Copyright (c) 2007-2008 Frederic Dalleau\n\n");
+
+ printf("Usage:\n"
+ "\tsbctester reference.wav checkfile.wav\n"
+ "\tsbctester integer\n"
+ "\n");
+
+ printf("To test the encoder:\n");
+ printf("\tUse a reference codec to encode original.wav to reference.sbc\n");
+ printf("\tUse sbcenc to encode original.wav to checkfile.sbc\n");
+ printf("\tDecode both file using the reference decoder\n");
+ printf("\tRun sbctester with these two wav files to get the result\n\n");
+
+ printf("\tA file called out.csv is generated to use the data in a\n");
+ printf("\tspreadsheet application or database.\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+ SNDFILE *sndref = NULL;
+ SNDFILE *sndtst = NULL;
+ SF_INFO infosref;
+ SF_INFO infostst;
+ char *ref;
+ char *tst;
+ int pass_rms, pass_absolute, pass, accuracy;
+
+ if (argc == 2) {
+ double db;
+
+ printf("Test sampletobits\n");
+ db = sampletobits((short) atoi(argv[1]), 1);
+ printf("db = %f\n", db);
+ exit(0);
+ }
+
+ if (argc < 3) {
+ usage();
+ exit(1);
+ }
+
+ ref = argv[1];
+ tst = argv[2];
+
+ printf("opening reference %s\n", ref);
+
+ sndref = sf_open(ref, SFM_READ, &infosref);
+ if (!sndref) {
+ printf("Failed to open reference file\n");
+ exit(1);
+ }
+
+ printf("opening testfile %s\n", tst);
+ sndtst = sf_open(tst, SFM_READ, &infostst);
+ if (!sndtst) {
+ printf("Failed to open test file\n");
+ sf_close(sndref);
+ exit(1);
+ }
+
+ printf("reference:\n\t%d frames,\n\t%d hz,\n\t%d channels\n",
+ (int) infosref.frames, (int) infosref.samplerate,
+ (int) infosref.channels);
+ printf("testfile:\n\t%d frames,\n\t%d hz,\n\t%d channels\n",
+ (int) infostst.frames, (int) infostst.samplerate,
+ (int) infostst.channels);
+
+ /* check number of channels */
+ if (infosref.channels > 2 || infostst.channels > 2) {
+ printf("Too many channels\n");
+ goto error;
+ }
+
+ /* compare number of samples */
+ if (infosref.samplerate != infostst.samplerate ||
+ infosref.channels != infostst.channels) {
+ printf("Cannot compare files with different charasteristics\n");
+ goto error;
+ }
+
+ accuracy = DEFACCURACY;
+ printf("Accuracy: %d\n", accuracy);
+
+ /* Condition 1 rms level */
+ pass_rms = calculate_rms_level(sndref, &infosref, sndtst, &infostst,
+ accuracy, "out.csv");
+ if (pass_rms < 0)
+ goto error;
+
+ /* Condition 2 absolute difference */
+ pass_absolute = check_absolute_diff(sndref, &infosref, sndtst,
+ &infostst, accuracy);
+ if (pass_absolute < 0)
+ goto error;
+
+ /* Verdict */
+ pass = pass_rms && pass_absolute;
+ printf("Verdict: %s\n", pass ? "pass" : "fail");
+
+ return 0;
+
+error:
+ sf_close(sndref);
+ sf_close(sndtst);
+
+ exit(1);
+}
diff --git a/utils/scripts/Makefile.am b/utils/scripts/Makefile.am
new file mode 100644
index 00000000..6a8eec7f
--- /dev/null
+++ b/utils/scripts/Makefile.am
@@ -0,0 +1,26 @@
+
+if PCMCIARULES
+rulesdir = $(sysconfdir)/udev
+
+rules_DATA = bluetooth.rules
+
+udevdir = $(libexecdir)/udev
+
+udev_SCRIPTS = bluetooth_serial
+endif
+
+EXTRA_DIST = bluetooth.rules bluetooth_serial bluetooth.init bluetooth.default
+
+MAINTAINERCLEANFILES = Makefile.in
+
+if INITSCRIPTS
+install-data-local:
+ $(INSTALL) -D -m 755 $(srcdir)/bluetooth.init $(DESTDIR)$(sysconfdir)/init.d/bluetooth
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)/default
+ [ -f $(DESTDIR)$(sysconfdir)/default/bluetooth ] || \
+ $(INSTALL_DATA) $(srcdir)/bluetooth.default $(DESTDIR)$(sysconfdir)/default/bluetooth
+
+uninstall-local:
+ @rm -f $(DESTDIR)$(sysconfdir)/init.d/bluetooth
+ @rm -f $(DESTDIR)$(sysconfdir)/default/bluetooth
+endif
diff --git a/utils/scripts/Makefile.in b/utils/scripts/Makefile.in
new file mode 100644
index 00000000..21376771
--- /dev/null
+++ b/utils/scripts/Makefile.in
@@ -0,0 +1,418 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = scripts
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(rulesdir)"
+udevSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(udev_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+rulesDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(rules_DATA)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@PCMCIARULES_TRUE@rulesdir = $(sysconfdir)/udev
+@PCMCIARULES_TRUE@rules_DATA = bluetooth.rules
+@PCMCIARULES_TRUE@udevdir = $(libexecdir)/udev
+@PCMCIARULES_TRUE@udev_SCRIPTS = bluetooth_serial
+EXTRA_DIST = bluetooth.rules bluetooth_serial bluetooth.init bluetooth.default
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu scripts/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-udevSCRIPTS: $(udev_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(udevdir)" || $(MKDIR_P) "$(DESTDIR)$(udevdir)"
+ @list='$(udev_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(udevSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(udevdir)/$$f'"; \
+ $(udevSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(udevdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-udevSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(udev_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(udevdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(udevdir)/$$f"; \
+ done
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-rulesDATA: $(rules_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(rulesdir)" || $(MKDIR_P) "$(DESTDIR)$(rulesdir)"
+ @list='$(rules_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(rulesDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(rulesdir)/$$f'"; \
+ $(rulesDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(rulesdir)/$$f"; \
+ done
+
+uninstall-rulesDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(rules_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(rulesdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(rulesdir)/$$f"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(rulesdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+@INITSCRIPTS_FALSE@uninstall-local:
+@INITSCRIPTS_FALSE@install-data-local:
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-rulesDATA \
+ install-udevSCRIPTS
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-local uninstall-rulesDATA \
+ uninstall-udevSCRIPTS
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-data-local install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-rulesDATA install-strip install-udevSCRIPTS \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-local uninstall-rulesDATA uninstall-udevSCRIPTS
+
+
+@INITSCRIPTS_TRUE@install-data-local:
+@INITSCRIPTS_TRUE@ $(INSTALL) -D -m 755 $(srcdir)/bluetooth.init $(DESTDIR)$(sysconfdir)/init.d/bluetooth
+@INITSCRIPTS_TRUE@ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)/default
+@INITSCRIPTS_TRUE@ [ -f $(DESTDIR)$(sysconfdir)/default/bluetooth ] || \
+@INITSCRIPTS_TRUE@ $(INSTALL_DATA) $(srcdir)/bluetooth.default $(DESTDIR)$(sysconfdir)/default/bluetooth
+
+@INITSCRIPTS_TRUE@uninstall-local:
+@INITSCRIPTS_TRUE@ @rm -f $(DESTDIR)$(sysconfdir)/init.d/bluetooth
+@INITSCRIPTS_TRUE@ @rm -f $(DESTDIR)$(sysconfdir)/default/bluetooth
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/scripts/bluetooth.default b/utils/scripts/bluetooth.default
new file mode 100644
index 00000000..b0c4493b
--- /dev/null
+++ b/utils/scripts/bluetooth.default
@@ -0,0 +1,4 @@
+# Bluetooth configuraton file
+
+# Run hid2hci (allowed values are "true" and "false")
+HID2HCI_ENABLE=true
diff --git a/utils/scripts/bluetooth.init b/utils/scripts/bluetooth.init
new file mode 100644
index 00000000..83260035
--- /dev/null
+++ b/utils/scripts/bluetooth.init
@@ -0,0 +1,51 @@
+#!/bin/sh
+#
+# Start/stop the Bluetooth daemons
+#
+
+set -e
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+NAME=bluetooth
+DESC="Bluetooth subsystem"
+
+DAEMON_NAME=hcid
+HID2HCI_NAME=hid2hci
+
+DAEMON_EXEC="`which $DAEMON_NAME || true`"
+HID2HCI_EXEC="`which $HID2HCI_NAME || true`"
+
+DAEMON_ENABLE=true
+HID2HCI_ENABLE=false
+
+DAEMON_CONFIG="/etc/bluetooth/hcid.conf"
+
+[ -e /etc/default/bluetooth ] && . /etc/default/bluetooth
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC:"
+ if $DAEMON_ENABLE && [ -x "$DAEMON_EXEC" ] && [ -f "$DAEMON_CONFIG" ] ; then
+ $DAEMON_EXEC -s -f $DAEMON_CONFIG
+ echo -n " $DAEMON_NAME"
+ fi
+ if $HID2HCI_ENABLE && [ -x "$HID2HCI_EXEC" ] ; then
+ $HID2HCI_EXEC --tohci > /dev/null 2>&1 || true
+ echo -n " $HID2HCI_NAME"
+ fi
+ echo "."
+ ;;
+ stop)
+ echo -n "Stopping $DESC:"
+ killall $DAEMON_NAME > /dev/null 2>&1 || true
+ echo -n " $DAEMON_NAME"
+ echo "."
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ echo "Usage: $N {start|stop}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/utils/scripts/bluetooth.rules b/utils/scripts/bluetooth.rules
new file mode 100644
index 00000000..0957225f
--- /dev/null
+++ b/utils/scripts/bluetooth.rules
@@ -0,0 +1,35 @@
+# Brain Boxes BL-620 Bluetooth Adapter
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="Brain Boxes", SYSFS{prod_id2}=="Bluetooth PC Card", ENV{HCIOPTS}="bboxes", RUN+="bluetooth_serial"
+
+# Xircom CreditCard Bluetooth Adapter
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="Xircom", SYSFS{prod_id3}=="CBT", ENV{HCIOPTS}="xircom", RUN+="bluetooth_serial"
+
+# Xircom RealPort2 Bluetooth Adapter
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="Xircom", SYSFS{prod_id3}=="CBT", ENV{HCIOPTS}="xircom", RUN+="bluetooth_serial"
+
+# IBM Bluetooth PC Card II
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="IBM", SYSFS{prod_id2}=="Bluetooth PC Card II", ENV{HCIOPTS}="tdk", RUN+="bluetooth_serial"
+
+# TDK Bluetooth PC Card
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="TDK", SYSFS{prod_id2}=="Bluetooth PC Card II", ENV{HCIOPTS}="tdk", RUN+="bluetooth_serial"
+
+# AmbiCom BT2000C Bluetooth PC/CF Card
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="AmbiCom BT2000C", SYSFS{prod_id2}=="Bluetooth PC/CF Card", ENV{HCIOPTS}="bt2000c", RUN+="bluetooth_serial"
+
+# COM One Platinium Bluetooth PC Card
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="COM1 SA", SYSFS{prod_id2}=="MC310 CARD", ENV{HCIOPTS}="comone", RUN+="bluetooth_serial"
+
+# Sphinx PICO Card
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="SPHINX", SYSFS{prod_id2}=="BT-CARD", ENV{HCIOPTS}="picocard", RUN+="bluetooth_serial"
+
+# H-Soft blue+Card
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="H-Soft", SYSFS{prod_id2}=="Blue+CARD", ENV{HCIOPTS}="$sysfs{manf_id},$sysfs{card_id}", RUN+="bluetooth_serial"
+
+# Compaq iPAQ Bluetooth Sleeve, Belkin F8T020, any other muppet who used an OXCF950 and didn't bother to program it appropriately.
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="CF CARD", SYSFS{prod_id2}=="GENERIC", ENV{HCIOPTS}="$sysfs{manf_id},$sysfs{card_id}", RUN+="bluetooth_serial"
+
+# Zoom Bluetooth Card and Sitecom CN-504 Card
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="PCMCIA", SYSFS{prod_id2}=="Bluetooth Card", ENV{HCIOPTS}="zoom", RUN+="bluetooth_serial"
+
+# CC&C BT0100M
+SUBSYSTEM=="tty", BUS=="pcmcia", SYSFS{prod_id1}=="Bluetooth BT0100M", ENV{HCIOPTS}="bcsp 115200", RUN+="bluetooth_serial"
diff --git a/utils/scripts/bluetooth_serial b/utils/scripts/bluetooth_serial
new file mode 100644
index 00000000..e5be6c2e
--- /dev/null
+++ b/utils/scripts/bluetooth_serial
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# bluetooth_serial
+#
+# Bluetooth serial PCMCIA card initialization
+#
+
+start_serial()
+{
+ if [ ! -x /bin/setserial -o ! -x /usr/sbin/hciattach ]; then
+ logger "$0: setserial or hciattach not executable, cannot start $DEVNAME"
+ return 1
+ fi
+
+ if [ "$BAUDBASE" != "" ]; then
+ /bin/setserial $DEVNAME baud_base $BAUDBASE
+ fi
+
+ /usr/sbin/hciattach $DEVNAME $HCIOPTS 2>&1 | logger -t hciattach
+}
+
+stop_serial()
+{
+ [ -x /bin/fuser ] || return 1
+
+ /bin/fuser -k -HUP $DEVNAME > /dev/null
+}
+
+case "$ACTION" in
+ add)
+ start_serial
+ ;;
+ remove)
+ stop_serial
+ ;;
+ *)
+ logger "Unknown action received $0: $ACTION"
+ ;;
+esac
diff --git a/utils/sdpd/Makefile.am b/utils/sdpd/Makefile.am
new file mode 100644
index 00000000..6ce2f85b
--- /dev/null
+++ b/utils/sdpd/Makefile.am
@@ -0,0 +1,11 @@
+
+noinst_LIBRARIES = libsdpserver.a
+
+libsdpserver_a_SOURCES = \
+ sdpd.h server.c cstate.c request.c service.c servicedb.c
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @GLIB_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/sdpd/Makefile.in b/utils/sdpd/Makefile.in
new file mode 100644
index 00000000..eca80a1c
--- /dev/null
+++ b/utils/sdpd/Makefile.in
@@ -0,0 +1,462 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = sdpd
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libsdpserver_a_AR = $(AR) $(ARFLAGS)
+libsdpserver_a_LIBADD =
+am_libsdpserver_a_OBJECTS = server.$(OBJEXT) cstate.$(OBJEXT) \
+ request.$(OBJEXT) service.$(OBJEXT) servicedb.$(OBJEXT)
+libsdpserver_a_OBJECTS = $(am_libsdpserver_a_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libsdpserver_a_SOURCES)
+DIST_SOURCES = $(libsdpserver_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LIBRARIES = libsdpserver.a
+libsdpserver_a_SOURCES = \
+ sdpd.h server.c cstate.c request.c service.c servicedb.c
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @GLIB_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu sdpd/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu sdpd/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libsdpserver.a: $(libsdpserver_a_OBJECTS) $(libsdpserver_a_DEPENDENCIES)
+ -rm -f libsdpserver.a
+ $(libsdpserver_a_AR) libsdpserver.a $(libsdpserver_a_OBJECTS) $(libsdpserver_a_LIBADD)
+ $(RANLIB) libsdpserver.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cstate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/request.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/service.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/servicedb.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/sdpd/cstate.c b/utils/sdpd/cstate.c
new file mode 100644
index 00000000..d0adf08a
--- /dev/null
+++ b/utils/sdpd/cstate.c
@@ -0,0 +1,95 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2002 Nokia Corporation
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "sdpd.h"
+
+typedef struct _sdp_cstate_list sdp_cstate_list_t;
+
+struct _sdp_cstate_list {
+ sdp_cstate_list_t *next;
+ uint32_t timestamp;
+ sdp_buf_t buf;
+};
+
+static sdp_cstate_list_t *cstates;
+
+// FIXME: should probably remove it when it's found
+sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate)
+{
+ sdp_cstate_list_t *p;
+
+ for (p = cstates; p; p = p->next)
+ if (p->timestamp == cstate->timestamp)
+ return &p->buf;
+ return 0;
+}
+
+uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf)
+{
+ sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t));
+ uint8_t *data = malloc(buf->data_size);
+
+ memcpy(data, buf->data, buf->data_size);
+ memset((char *)cstate, 0, sizeof(sdp_cstate_list_t));
+ cstate->buf.data = data;
+ cstate->buf.data_size = buf->data_size;
+ cstate->buf.buf_size = buf->data_size;
+ cstate->timestamp = sdp_get_time();
+ cstate->next = cstates;
+ cstates = cstate;
+ return cstate->timestamp;
+}
+
+/*
+ * A simple function which returns the time of day in
+ * seconds. Used for updating the service db state
+ * attribute of the service record of the SDP server
+ */
+uint32_t sdp_get_time()
+{
+ /*
+ * To handle failure in gettimeofday, so an old
+ * value is returned and service does not fail
+ */
+ static struct timeval tm;
+
+ gettimeofday(&tm, NULL);
+ return (uint32_t) tm.tv_sec;
+}
diff --git a/utils/sdpd/request.c b/utils/sdpd/request.c
new file mode 100644
index 00000000..9020dd38
--- /dev/null
+++ b/utils/sdpd/request.c
@@ -0,0 +1,923 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2002 Nokia Corporation
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <netinet/in.h>
+
+#include "sdpd.h"
+#include "logging.h"
+
+#define MIN(x, y) ((x) < (y))? (x): (y)
+
+/* Additional values for checking datatype (not in spec) */
+#define SDP_TYPE_UUID 0xfe
+#define SDP_TYPE_ANY 0xff
+
+/*
+ * Generic data element sequence extractor. Builds
+ * 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
+ */
+static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType)
+{
+ uint8_t seqType;
+ int scanned, data_size = 0;
+ short numberOfElements = 0;
+ int seqlen = 0;
+ sdp_list_t *pSeq = NULL;
+ uint8_t dataType;
+ int status = 0;
+ const uint8_t *p;
+ int bufsize;
+
+ scanned = sdp_extract_seqtype_safe(buf, len, &seqType, &data_size);
+
+ debug("Seq type : %d", seqType);
+ if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) {
+ error("Unknown seq type");
+ return -1;
+ }
+ p = buf + scanned;
+ bufsize = len - scanned;
+
+ debug("Data size : %d", data_size);
+
+ for (;;) {
+ char *pElem = NULL;
+ int localSeqLength = 0;
+
+ if (bufsize < sizeof(uint8_t)) {
+ debug("->Unexpected end of buffer");
+ return -1;
+ }
+
+ dataType = *(uint8_t *)p;
+ debug("Data type: 0x%02x", dataType);
+
+ if (expectedType == SDP_TYPE_UUID) {
+ if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) {
+ debug("->Unexpected Data type (expected UUID_ANY)");
+ return -1;
+ }
+ } else if (expectedType != SDP_TYPE_ANY && dataType != expectedType) {
+ debug("->Unexpected Data type (expected 0x%02x)", expectedType);
+ return -1;
+ }
+
+ switch (dataType) {
+ case SDP_UINT16:
+ p += sizeof(uint8_t);
+ seqlen += sizeof(uint8_t);
+ bufsize -= sizeof(uint8_t);
+ if (bufsize < sizeof(uint16_t)) {
+ debug("->Unexpected end of buffer");
+ return -1;
+ }
+
+ pElem = malloc(sizeof(uint16_t));
+ bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem);
+ p += sizeof(uint16_t);
+ seqlen += sizeof(uint16_t);
+ bufsize -= sizeof(uint16_t);
+ break;
+ case SDP_UINT32:
+ p += sizeof(uint8_t);
+ seqlen += sizeof(uint8_t);
+ bufsize -= sizeof(uint8_t);
+ if (bufsize < (int)sizeof(uint32_t)) {
+ debug("->Unexpected end of buffer");
+ return -1;
+ }
+
+ pElem = malloc(sizeof(uint32_t));
+ bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem);
+ p += sizeof(uint32_t);
+ seqlen += sizeof(uint32_t);
+ bufsize -= sizeof(uint32_t);
+ break;
+ case SDP_UUID16:
+ case SDP_UUID32:
+ case SDP_UUID128:
+ pElem = malloc(sizeof(uuid_t));
+ status = sdp_uuid_extract_safe(p, bufsize, (uuid_t *) pElem, &localSeqLength);
+ if (status == 0) {
+ seqlen += localSeqLength;
+ p += localSeqLength;
+ bufsize -= localSeqLength;
+ }
+ break;
+ default:
+ return -1;
+ }
+ if (status == 0) {
+ pSeq = sdp_list_append(pSeq, pElem);
+ numberOfElements++;
+ debug("No of elements : %d", numberOfElements);
+
+ if (seqlen == data_size)
+ break;
+ else if (seqlen > data_size || seqlen > len)
+ return -1;
+ } else
+ free(pElem);
+ }
+ *svcReqSeq = pSeq;
+ scanned += seqlen;
+ *pDataType = dataType;
+ return scanned;
+}
+
+static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate)
+{
+ uint8_t *pdata = buf->data + buf->data_size;
+ int length = 0;
+
+ if (cstate) {
+ debug("Non null sdp_cstate_t id : 0x%lx", cstate->timestamp);
+ *(uint8_t *)pdata = sizeof(sdp_cont_state_t);
+ pdata += sizeof(uint8_t);
+ length += sizeof(uint8_t);
+ memcpy(pdata, cstate, sizeof(sdp_cont_state_t));
+ length += sizeof(sdp_cont_state_t);
+ } else {
+ // set "null" continuation state
+ *(uint8_t *)pdata = 0;
+ pdata += sizeof(uint8_t);
+ length += sizeof(uint8_t);
+ }
+ buf->data_size += length;
+ return length;
+}
+
+static sdp_cont_state_t *sdp_cstate_get(uint8_t *buffer)
+{
+ uint8_t *pdata = buffer;
+ uint8_t cStateSize = *(uint8_t *)pdata;
+
+ /*
+ * Check if continuation state exists, if yes attempt
+ * to get response remainder from cache, else send error
+ */
+ debug("Continuation State size : %d", cStateSize);
+
+ pdata += sizeof(uint8_t);
+ if (cStateSize != 0) {
+ sdp_cont_state_t *cstate = malloc(sizeof(sdp_cont_state_t));
+ if (!cstate)
+ return NULL;
+ memcpy(cstate, (sdp_cont_state_t *)pdata, sizeof(sdp_cont_state_t));
+ debug("Cstate TS : 0x%lx", cstate->timestamp);
+ debug("Bytes sent : %d", cstate->cStateValue.maxBytesSent);
+ return cstate;
+ }
+ return NULL;
+}
+
+/*
+ * The matching process is defined as "each and every UUID
+ * 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.
+ *
+ * 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.
+ */
+static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern)
+{
+ /*
+ * The target is a sorted list, so we need not look
+ * at all elements to confirm existence of an element
+ * from the search pattern
+ */
+ int patlen = sdp_list_len(pattern);
+
+ if (patlen < sdp_list_len(search))
+ return -1;
+ for (; search; search = search->next) {
+ uuid_t *uuid128;
+ void *data = search->data;
+ sdp_list_t *list;
+ if (data == NULL)
+ return -1;
+
+ // create 128-bit form of the search UUID
+ uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);
+ list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);
+ bt_free(uuid128);
+ if (!list)
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Service search request PDU. This method extracts the search pattern
+ * (a sequence of UUIDs) and calls the matching function
+ * to find matching services
+ */
+static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
+{
+ int status = 0, i, plen, mlen, mtu, scanned;
+ sdp_list_t *pattern = NULL;
+ uint16_t expected, actual, rsp_count = 0;
+ uint8_t dtd;
+ sdp_cont_state_t *cstate = NULL;
+ uint8_t *pCacheBuffer = NULL;
+ int handleSize = 0;
+ uint32_t cStateId = 0;
+ short *pTotalRecordCount, *pCurrentRecordCount;
+ uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
+
+ scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
+ &pattern, &dtd, SDP_TYPE_UUID);
+
+ if (scanned == -1) {
+ status = SDP_INVALID_SYNTAX;
+ goto done;
+ }
+ pdata += scanned;
+
+ plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
+ mlen = scanned + sizeof(uint16_t) + 1;
+ // ensure we don't read past buffer
+ if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) {
+ status = SDP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ expected = ntohs(bt_get_unaligned((uint16_t *)pdata));
+
+ debug("Expected count: %d", expected);
+ debug("Bytes scanned : %d", scanned);
+
+ pdata += sizeof(uint16_t);
+
+ /*
+ * Check if continuation state exists, if yes attempt
+ * to get rsp remainder from cache, else send error
+ */
+ cstate = sdp_cstate_get(pdata);
+
+ mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE;
+ actual = MIN(expected, mtu >> 2);
+
+ /* make space in the rsp buffer for total and current record counts */
+ pdata = buf->data;
+
+ /* total service record count = 0 */
+ pTotalRecordCount = (short *)pdata;
+ bt_put_unaligned(0, (uint16_t *)pdata);
+ pdata += sizeof(uint16_t);
+ buf->data_size += sizeof(uint16_t);
+
+ /* current service record count = 0 */
+ pCurrentRecordCount = (short *)pdata;
+ bt_put_unaligned(0, (uint16_t *)pdata);
+ pdata += sizeof(uint16_t);
+ buf->data_size += sizeof(uint16_t);
+
+ if (cstate == NULL) {
+ /* for every record in the DB, do a pattern search */
+ sdp_list_t *list = sdp_get_record_list();
+
+ handleSize = 0;
+ for (; list && rsp_count < expected; list = list->next) {
+ sdp_record_t *rec = (sdp_record_t *) list->data;
+
+ debug("Checking svcRec : 0x%x", rec->handle);
+
+ if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
+ sdp_check_access(rec->handle, &req->device)) {
+ rsp_count++;
+ bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata);
+ pdata += sizeof(uint32_t);
+ handleSize += sizeof(uint32_t);
+ }
+ }
+
+ debug("Match count: %d", rsp_count);
+
+ buf->data_size += handleSize;
+ bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
+ bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount);
+
+ if (rsp_count > actual) {
+ /* cache the rsp and generate a continuation state */
+ cStateId = sdp_cstate_alloc_buf(buf);
+ /*
+ * subtract handleSize since we now send only
+ * a subset of handles
+ */
+ buf->data_size -= handleSize;
+ } else {
+ /* NULL continuation state */
+ sdp_set_cstate_pdu(buf, NULL);
+ }
+ }
+
+ /* under both the conditions below, the rsp buffer is not built yet */
+ if (cstate || cStateId > 0) {
+ short lastIndex = 0;
+
+ if (cstate) {
+ /*
+ * Get the previous sdp_cont_state_t and obtain
+ * the cached rsp
+ */
+ sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
+ if (pCache) {
+ pCacheBuffer = pCache->data;
+ /* get the rsp_count from the cached buffer */
+ rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer));
+
+ /* get index of the last sdp_record_t sent */
+ lastIndex = cstate->cStateValue.lastIndexSent;
+ } else {
+ status = SDP_INVALID_CSTATE;
+ goto done;
+ }
+ } else {
+ pCacheBuffer = buf->data;
+ lastIndex = 0;
+ }
+
+ /*
+ * Set the local buffer pointer to after the
+ * current record count and increment the cached
+ * buffer pointer to beyond the counters
+ */
+ pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t);
+
+ /* increment beyond the totalCount and the currentCount */
+ pCacheBuffer += 2 * sizeof(uint16_t);
+
+ if (cstate) {
+ handleSize = 0;
+ for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) {
+ bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata);
+ pdata += sizeof(uint32_t);
+ handleSize += sizeof(uint32_t);
+ }
+ } else {
+ handleSize = actual << 2;
+ i = actual;
+ }
+
+ buf->data_size += handleSize;
+ bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
+ bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount);
+
+ if (i == rsp_count) {
+ /* set "null" continuationState */
+ sdp_set_cstate_pdu(buf, NULL);
+ } else {
+ /*
+ * there's more: set lastIndexSent to
+ * the new value and move on
+ */
+ sdp_cont_state_t newState;
+
+ debug("Setting non-NULL sdp_cstate_t");
+
+ if (cstate)
+ memcpy((char *)&newState, cstate, sizeof(sdp_cont_state_t));
+ else {
+ memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
+ newState.timestamp = cStateId;
+ }
+ newState.cStateValue.lastIndexSent = i;
+ sdp_set_cstate_pdu(buf, &newState);
+ }
+ }
+
+done:
+ if (cstate)
+ free(cstate);
+ if (pattern)
+ sdp_list_free(pattern, free);
+
+ return status;
+}
+
+/*
+ * Extract attribute identifiers from the request PDU.
+ * Clients could request a subset of attributes (by id)
+ * from a service record, instead of the whole set. The
+ * requested identifiers are present in the PDU form of
+ * the request
+ */
+static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, uint8_t dtd, sdp_buf_t *buf)
+{
+ if (!rec)
+ return SDP_INVALID_RECORD_HANDLE;
+
+ if (seq)
+ debug("Entries in attr seq : %d", sdp_list_len(seq));
+ else
+ debug("NULL attribute descriptor");
+
+ debug("AttrDataType : %d", dtd);
+
+ if (seq == NULL) {
+ debug("Attribute sequence is NULL");
+ return 0;
+ }
+ if (dtd == SDP_UINT16)
+ for (; seq; seq = seq->next) {
+ uint16_t attr = bt_get_unaligned((uint16_t *)seq->data);
+ sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);
+ if (a)
+ sdp_append_to_pdu(buf, a);
+ }
+ else if (dtd == SDP_UINT32) {
+ sdp_buf_t pdu;
+ sdp_gen_record_pdu(rec, &pdu);
+ for (; seq; seq = seq->next) {
+ uint32_t range = bt_get_unaligned((uint32_t *)seq->data);
+ uint16_t attr;
+ uint16_t low = (0xffff0000 & range) >> 16;
+ uint16_t high = 0x0000ffff & range;
+ sdp_data_t *data;
+
+ debug("attr range : 0x%x", range);
+ debug("Low id : 0x%x", low);
+ debug("High id : 0x%x", high);
+
+ if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {
+ /* copy it */
+ memcpy(buf->data, pdu.data, pdu.data_size);
+ buf->data_size = pdu.data_size;
+ break;
+ }
+ /* (else) sub-range of attributes */
+ for (attr = low; attr < high; attr++) {
+ data = sdp_data_get(rec, attr);
+ if (data)
+ sdp_append_to_pdu(buf, data);
+ }
+ data = sdp_data_get(rec, high);
+ if (data)
+ sdp_append_to_pdu(buf, data);
+ }
+ free(pdu.data);
+ } else {
+ error("Unexpected data type : 0x%x", dtd);
+ error("Expect uint16_t or uint32_t");
+ return SDP_INVALID_SYNTAX;
+ }
+ return 0;
+}
+
+/*
+ * A request for the attributes of a service record.
+ * First check if the service record (specified by
+ * service record handle) exists, then call the attribute
+ * streaming function
+ */
+static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
+{
+ sdp_cont_state_t *cstate = NULL;
+ uint8_t *pResponse = NULL;
+ short cstate_size = 0;
+ sdp_list_t *seq = NULL;
+ uint8_t dtd = 0;
+ int scanned = 0;
+ int max_rsp_size;
+ int status = 0, plen, mlen;
+ uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
+ uint32_t handle = ntohl(bt_get_unaligned((uint32_t *)pdata));
+
+ pdata += sizeof(uint32_t);
+ max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata));
+ pdata += sizeof(uint16_t);
+
+ /* extract the attribute list */
+ scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
+ &seq, &dtd, SDP_TYPE_ANY);
+ if (scanned == -1) {
+ status = SDP_INVALID_SYNTAX;
+ goto done;
+ }
+ pdata += scanned;
+
+ plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
+ mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1;
+ // ensure we don't read past buffer
+ if (plen < mlen || plen != mlen + *(uint8_t *)pdata) {
+ status = SDP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ /*
+ * if continuation state exists, attempt
+ * to get rsp remainder from cache, else send error
+ */
+ cstate = sdp_cstate_get(pdata);
+
+ debug("SvcRecHandle : 0x%x", handle);
+ debug("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) -
+ sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
+
+ /* pull header for AttributeList byte count */
+ buf->data += sizeof(uint16_t);
+ buf->buf_size -= sizeof(uint16_t);
+
+ if (cstate) {
+ sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
+
+ debug("Obtained cached rsp : %p", pCache);
+
+ if (pCache) {
+ short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent);
+ pResponse = pCache->data;
+ memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
+ buf->data_size += sent;
+ cstate->cStateValue.maxBytesSent += sent;
+
+ debug("Response size : %d sending now : %d bytes sent so far : %d",
+ pCache->data_size, sent, cstate->cStateValue.maxBytesSent);
+ if (cstate->cStateValue.maxBytesSent == pCache->data_size)
+ cstate_size = sdp_set_cstate_pdu(buf, NULL);
+ else
+ cstate_size = sdp_set_cstate_pdu(buf, cstate);
+ } else {
+ status = SDP_INVALID_CSTATE;
+ error("NULL cache buffer and non-NULL continuation state");
+ }
+ } else {
+ sdp_record_t *rec = sdp_record_find(handle);
+ status = extract_attrs(rec, seq, dtd, buf);
+ if (buf->data_size > max_rsp_size) {
+ sdp_cont_state_t newState;
+
+ memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
+ newState.timestamp = sdp_cstate_alloc_buf(buf);
+ /*
+ * Reset the buffer size to the maximum expected and
+ * set the sdp_cont_state_t
+ */
+ debug("Creating continuation state of size : %d", buf->data_size);
+ buf->data_size = max_rsp_size;
+ newState.cStateValue.maxBytesSent = max_rsp_size;
+ cstate_size = sdp_set_cstate_pdu(buf, &newState);
+ } else {
+ if (buf->data_size == 0)
+ sdp_append_to_buf(buf, 0, 0);
+ cstate_size = sdp_set_cstate_pdu(buf, NULL);
+ }
+ }
+
+ // push header
+ buf->data -= sizeof(uint16_t);
+ buf->buf_size += sizeof(uint16_t);
+
+done:
+ if (cstate)
+ free(cstate);
+ if (seq)
+ sdp_list_free(seq, free);
+ if (status)
+ return status;
+
+ /* set attribute list byte count */
+ bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
+ buf->data_size += sizeof(uint16_t);
+ return 0;
+}
+
+/*
+ * combined service search and attribute extraction
+ */
+static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
+{
+ int status = 0, plen, totscanned;
+ uint8_t *pdata, *pResponse = NULL;
+ int scanned, max, rsp_count = 0;
+ sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
+ sdp_cont_state_t *cstate = NULL;
+ short cstate_size = 0;
+ uint8_t dtd = 0;
+ sdp_buf_t tmpbuf;
+
+ tmpbuf.data = NULL;
+ pdata = req->buf + sizeof(sdp_pdu_hdr_t);
+ scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
+ &pattern, &dtd, SDP_TYPE_UUID);
+ if (scanned == -1) {
+ status = SDP_INVALID_SYNTAX;
+ goto done;
+ }
+ totscanned = scanned;
+
+ debug("Bytes scanned: %d", scanned);
+
+ pdata += scanned;
+ max = ntohs(bt_get_unaligned((uint16_t *)pdata));
+ pdata += sizeof(uint16_t);
+
+ debug("Max Attr expected: %d", max);
+
+ /* extract the attribute list */
+ scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
+ &seq, &dtd, SDP_TYPE_ANY);
+ if (scanned == -1) {
+ status = SDP_INVALID_SYNTAX;
+ goto done;
+ }
+ pdata += scanned;
+ totscanned += scanned + sizeof(uint16_t) + 1;
+
+ plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
+ if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {
+ status = SDP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ /*
+ * if continuation state exists attempt
+ * to get rsp remainder from cache, else send error
+ */
+ cstate = sdp_cstate_get(pdata); // continuation information
+
+ svcList = sdp_get_record_list();
+
+ tmpbuf.data = malloc(USHRT_MAX);
+ tmpbuf.data_size = 0;
+ 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))
+ */
+ max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
+
+ /* pull header for AttributeList byte count */
+ buf->data += sizeof(uint16_t);
+ buf->buf_size -= sizeof(uint16_t);
+
+ if (cstate == NULL) {
+ /* no continuation state -> create new response */
+ sdp_list_t *p;
+ for (p = svcList; p; p = p->next) {
+ sdp_record_t *rec = (sdp_record_t *) p->data;
+ if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
+ sdp_check_access(rec->handle, &req->device)) {
+ rsp_count++;
+ status = extract_attrs(rec, seq, dtd, &tmpbuf);
+
+ debug("Response count : %d", rsp_count);
+ debug("Local PDU size : %d", tmpbuf.data_size);
+ if (status) {
+ debug("Extract attr from record returns err");
+ break;
+ }
+ if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
+ // to be sure no relocations
+ sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
+ tmpbuf.data_size = 0;
+ memset(tmpbuf.data, 0, USHRT_MAX);
+ } else {
+ error("Relocation needed");
+ break;
+ }
+ debug("Net PDU size : %d", buf->data_size);
+ }
+ }
+ if (buf->data_size > max) {
+ sdp_cont_state_t newState;
+
+ memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
+ newState.timestamp = sdp_cstate_alloc_buf(buf);
+ /*
+ * Reset the buffer size to the maximum expected and
+ * set the sdp_cont_state_t
+ */
+ buf->data_size = max;
+ newState.cStateValue.maxBytesSent = max;
+ cstate_size = sdp_set_cstate_pdu(buf, &newState);
+ } else
+ cstate_size = sdp_set_cstate_pdu(buf, NULL);
+ } else {
+ /* continuation State exists -> get from cache */
+ sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
+ if (pCache) {
+ uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
+ pResponse = pCache->data;
+ memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
+ buf->data_size += sent;
+ cstate->cStateValue.maxBytesSent += sent;
+ if (cstate->cStateValue.maxBytesSent == pCache->data_size)
+ cstate_size = sdp_set_cstate_pdu(buf, NULL);
+ else
+ cstate_size = sdp_set_cstate_pdu(buf, cstate);
+ } else {
+ status = SDP_INVALID_CSTATE;
+ debug("Non-null continuation state, but null cache buffer");
+ }
+ }
+
+ if (!rsp_count && !cstate) {
+ // found nothing
+ buf->data_size = 0;
+ sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
+ sdp_set_cstate_pdu(buf, NULL);
+ }
+
+ // push header
+ buf->data -= sizeof(uint16_t);
+ buf->buf_size += sizeof(uint16_t);
+
+ if (!status) {
+ /* set attribute list byte count */
+ bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
+ buf->data_size += sizeof(uint16_t);
+ }
+
+done:
+ if (cstate)
+ free(cstate);
+ if (tmpbuf.data)
+ free(tmpbuf.data);
+ if (pattern)
+ sdp_list_free(pattern, free);
+ if (seq)
+ sdp_list_free(seq, free);
+ return status;
+}
+
+/*
+ * Top level request processor. Calls the appropriate processing
+ * function based on request type. Handles service registration
+ * client requests also.
+ */
+static void process_request(sdp_req_t *req)
+{
+ sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;
+ sdp_pdu_hdr_t *rsphdr;
+ sdp_buf_t rsp;
+ uint8_t *buf = malloc(USHRT_MAX);
+ int sent = 0;
+ int status = SDP_INVALID_SYNTAX;
+
+ memset(buf, 0, USHRT_MAX);
+ rsp.data = buf + sizeof(sdp_pdu_hdr_t);
+ rsp.data_size = 0;
+ rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);
+ rsphdr = (sdp_pdu_hdr_t *)buf;
+
+ if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {
+ status = SDP_INVALID_PDU_SIZE;
+ goto send_rsp;
+ }
+ switch (reqhdr->pdu_id) {
+ case SDP_SVC_SEARCH_REQ:
+ debug("Got a svc srch req");
+ status = service_search_req(req, &rsp);
+ rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
+ break;
+ case SDP_SVC_ATTR_REQ:
+ debug("Got a svc attr req");
+ status = service_attr_req(req, &rsp);
+ rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
+ break;
+ case SDP_SVC_SEARCH_ATTR_REQ:
+ debug("Got a svc srch attr req");
+ status = service_search_attr_req(req, &rsp);
+ rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
+ break;
+ /* Following requests are allowed only for local connections */
+ case SDP_SVC_REGISTER_REQ:
+ debug("Service register request");
+ if (req->local) {
+ status = service_register_req(req, &rsp);
+ rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
+ }
+ break;
+ case SDP_SVC_UPDATE_REQ:
+ debug("Service update request");
+ if (req->local) {
+ status = service_update_req(req, &rsp);
+ rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
+ }
+ break;
+ case SDP_SVC_REMOVE_REQ:
+ debug("Service removal request");
+ if (req->local) {
+ status = service_remove_req(req, &rsp);
+ rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
+ }
+ break;
+ default:
+ error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
+ status = SDP_INVALID_SYNTAX;
+ break;
+ }
+
+send_rsp:
+ if (status) {
+ rsphdr->pdu_id = SDP_ERROR_RSP;
+ bt_put_unaligned(htons(status), (uint16_t *)rsp.data);
+ rsp.data_size = sizeof(uint16_t);
+ }
+
+ debug("Sending rsp. status %d", status);
+
+ rsphdr->tid = reqhdr->tid;
+ rsphdr->plen = htons(rsp.data_size);
+
+ /* point back to the real buffer start and set the real rsp length */
+ rsp.data_size += sizeof(sdp_pdu_hdr_t);
+ rsp.data = buf;
+
+ /* stream the rsp PDU */
+ sent = send(req->sock, rsp.data, rsp.data_size, 0);
+
+ debug("Bytes Sent : %d", sent);
+
+ free(rsp.data);
+ free(req->buf);
+}
+
+void handle_request(int sk, uint8_t *data, int len)
+{
+ struct sockaddr_l2 sa;
+ socklen_t size;
+ sdp_req_t req;
+
+ size = sizeof(sa);
+ if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0)
+ return;
+
+ 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);
+ 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);
+ bacpy(&req.device, &sa.l2_bdaddr);
+ } else {
+ bacpy(&req.device, BDADDR_ANY);
+ bacpy(&req.bdaddr, BDADDR_LOCAL);
+ req.mtu = 2048;
+ req.local = 1;
+ }
+
+ req.sock = sk;
+ req.buf = data;
+ req.len = len;
+
+ process_request(&req);
+}
diff --git a/utils/sdpd/sdpd.h b/utils/sdpd/sdpd.h
new file mode 100644
index 00000000..30f05df4
--- /dev/null
+++ b/utils/sdpd/sdpd.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2002 Nokia Corporation
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+typedef struct request {
+ bdaddr_t device;
+ bdaddr_t bdaddr;
+ int local;
+ int sock;
+ int mtu;
+ int flags;
+ uint8_t *buf;
+ int len;
+} sdp_req_t;
+
+void handle_request(int sk, uint8_t *data, int len);
+
+int service_register_req(sdp_req_t *req, sdp_buf_t *rsp);
+int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
+int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp);
+
+void register_public_browse_group(void);
+void register_server_service(void);
+void register_device_id(const uint16_t vendor, const uint16_t product,
+ const uint16_t version);
+
+typedef struct {
+ uint32_t timestamp;
+ union {
+ uint16_t maxBytesSent;
+ uint16_t lastIndexSent;
+ } cStateValue;
+} sdp_cont_state_t;
+
+#define SDP_CONT_STATE_SIZE (sizeof(uint8_t) + sizeof(sdp_cont_state_t))
+
+sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate);
+void sdp_cstate_cache_init(void);
+void sdp_cstate_clean_buf(void);
+uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf);
+
+void sdp_svcdb_reset(void);
+void sdp_svcdb_collect_all(int sock);
+void sdp_svcdb_set_collectable(sdp_record_t *rec, int sock);
+void sdp_svcdb_collect(sdp_record_t *rec);
+sdp_record_t *sdp_record_find(uint32_t handle);
+void sdp_record_add(bdaddr_t *device, sdp_record_t *rec);
+int sdp_record_remove(uint32_t handle);
+sdp_list_t *sdp_get_record_list(void);
+sdp_list_t *sdp_get_access_list(void);
+int sdp_check_access(uint32_t handle, bdaddr_t *device);
+uint32_t sdp_next_handle(void);
+
+uint32_t sdp_get_time();
+
+#define SDP_SERVER_COMPAT (1 << 0)
+#define SDP_SERVER_MASTER (1 << 1)
+
+int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags);
+void stop_sdp_server(void);
+
+int add_record_to_server(bdaddr_t *src, sdp_record_t *rec);
+int remove_record_from_server(uint32_t handle);
+
+typedef void (*service_classes_callback_t) (const bdaddr_t *bdaddr, uint8_t value);
+
+uint8_t get_service_classes(const bdaddr_t *bdaddr);
+void set_service_classes_callback(service_classes_callback_t callback);
+void create_ext_inquiry_response(const char *name, uint8_t *data);
diff --git a/utils/sdpd/server.c b/utils/sdpd/server.c
new file mode 100644
index 00000000..1524d1c0
--- /dev/null
+++ b/utils/sdpd/server.c
@@ -0,0 +1,280 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2002 Nokia Corporation
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "sdpd.h"
+
+static GIOChannel *l2cap_io = NULL, *unix_io = NULL;
+
+static int l2cap_sock, unix_sock;
+
+/*
+ * SDP server initialization on startup includes creating the
+ * l2cap and unix sockets over which discovery and registration clients
+ * access us respectively
+ */
+static int init_server(uint16_t mtu, int master, int compat)
+{
+ struct l2cap_options opts;
+ struct sockaddr_l2 l2addr;
+ struct sockaddr_un unaddr;
+ socklen_t optlen;
+
+ /* Register the public browse group root */
+ register_public_browse_group();
+
+ /* Register the SDP server's service record */
+ register_server_service();
+
+ /* Create L2CAP socket */
+ l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (l2cap_sock < 0) {
+ error("opening L2CAP socket: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&l2addr, 0, sizeof(l2addr));
+ l2addr.l2_family = AF_BLUETOOTH;
+ bacpy(&l2addr.l2_bdaddr, BDADDR_ANY);
+ l2addr.l2_psm = htobs(SDP_PSM);
+
+ if (bind(l2cap_sock, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
+ error("binding L2CAP socket: %s", strerror(errno));
+ return -1;
+ }
+
+ if (master) {
+ int opt = L2CAP_LM_MASTER;
+ if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) {
+ error("setsockopt: %s", strerror(errno));
+ return -1;
+ }
+ }
+
+ if (mtu > 0) {
+ memset(&opts, 0, sizeof(opts));
+ optlen = sizeof(opts);
+
+ if (getsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
+ error("getsockopt: %s", strerror(errno));
+ return -1;
+ }
+
+ opts.omtu = mtu;
+ opts.imtu = mtu;
+
+ if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
+ error("setsockopt: %s", strerror(errno));
+ return -1;
+ }
+ }
+
+ listen(l2cap_sock, 5);
+
+ if (!compat) {
+ unix_sock = -1;
+ return 0;
+ }
+
+ /* Create local Unix socket */
+ unix_sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (unix_sock < 0) {
+ error("opening UNIX socket: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&unaddr, 0, sizeof(unaddr));
+ unaddr.sun_family = AF_UNIX;
+ strcpy(unaddr.sun_path, SDP_UNIX_PATH);
+
+ unlink(unaddr.sun_path);
+
+ if (bind(unix_sock, (struct sockaddr *) &unaddr, sizeof(unaddr)) < 0) {
+ error("binding UNIX socket: %s", strerror(errno));
+ return -1;
+ }
+
+ listen(unix_sock, 5);
+
+ chmod(SDP_UNIX_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+
+ return 0;
+}
+
+static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ sdp_pdu_hdr_t hdr;
+ uint8_t *buf;
+ int sk, len, size;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ sdp_svcdb_collect_all(sk);
+ return FALSE;
+ }
+
+ len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
+ if (len <= 0) {
+ sdp_svcdb_collect_all(sk);
+ return FALSE;
+ }
+
+ size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
+ buf = malloc(size);
+ if (!buf)
+ return TRUE;
+
+ len = recv(sk, buf, size, 0);
+ if (len <= 0) {
+ sdp_svcdb_collect_all(sk);
+ return FALSE;
+ }
+
+ handle_request(sk, buf, len);
+
+ return TRUE;
+}
+
+static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ GIOChannel *io;
+ int nsk;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ g_io_channel_unref(chan);
+ return FALSE;
+ }
+
+ if (data == &l2cap_sock) {
+ struct sockaddr_l2 addr;
+ socklen_t len = sizeof(addr);
+
+ nsk = accept(l2cap_sock, (struct sockaddr *) &addr, &len);
+ } else if (data == &unix_sock) {
+ struct sockaddr_un addr;
+ socklen_t len = sizeof(addr);
+
+ nsk = accept(unix_sock, (struct sockaddr *) &addr, &len);
+ } else
+ return FALSE;
+
+ if (nsk < 0) {
+ error("Can't accept connection: %s", strerror(errno));
+ return TRUE;
+ }
+
+ io = g_io_channel_unix_new(nsk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ io_session_event, data);
+
+ g_io_channel_unref(io);
+
+ return TRUE;
+}
+
+int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags)
+{
+ int compat = flags & SDP_SERVER_COMPAT;
+ int master = flags & SDP_SERVER_MASTER;
+
+ info("Starting SDP server");
+
+ if (init_server(mtu, master, compat) < 0) {
+ error("Server initialization failed");
+ return -1;
+ }
+
+ if (did && strlen(did) > 0) {
+ const char *ptr = did;
+ uint16_t vid = 0x0000, pid = 0x0000, ver = 0x0000;
+
+ vid = (uint16_t) strtol(ptr, NULL, 16);
+ ptr = strchr(ptr, ':');
+ if (ptr) {
+ pid = (uint16_t) strtol(ptr + 1, NULL, 16);
+ ptr = strchr(ptr + 1, ':');
+ if (ptr)
+ ver = (uint16_t) strtol(ptr + 1, NULL, 16);
+ register_device_id(vid, pid, ver);
+ }
+ }
+
+ l2cap_io = g_io_channel_unix_new(l2cap_sock);
+ g_io_channel_set_close_on_unref(l2cap_io, TRUE);
+
+ g_io_add_watch(l2cap_io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ io_accept_event, &l2cap_sock);
+
+ if (compat && unix_sock > fileno(stderr)) {
+ unix_io = g_io_channel_unix_new(unix_sock);
+ g_io_channel_set_close_on_unref(unix_io, TRUE);
+
+ g_io_add_watch(unix_io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ io_accept_event, &unix_sock);
+ }
+
+ return 0;
+}
+
+void stop_sdp_server(void)
+{
+ info("Stopping SDP server");
+
+ sdp_svcdb_reset();
+
+ if (unix_io)
+ g_io_channel_unref(unix_io);
+
+ if (l2cap_io)
+ g_io_channel_unref(l2cap_io);
+}
diff --git a/utils/sdpd/service.c b/utils/sdpd/service.c
new file mode 100644
index 00000000..a1072cd6
--- /dev/null
+++ b/utils/sdpd/service.c
@@ -0,0 +1,658 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2002 Nokia Corporation
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <netinet/in.h>
+
+#include "sdpd.h"
+#include "logging.h"
+
+static sdp_record_t *server = NULL;
+
+static uint8_t service_classes = 0x00;
+static service_classes_callback_t service_classes_callback = NULL;
+
+static uint16_t did_vendor = 0x0000;
+static uint16_t did_product = 0x0000;
+static uint16_t did_version = 0x0000;
+
+/*
+ * List of version numbers supported by the SDP server.
+ * Add to this list when newer versions are supported.
+ */
+static sdp_version_t sdpVnumArray[1] = {
+ { 1, 0 }
+};
+static const int sdpServerVnumEntries = 1;
+
+/*
+ * The service database state is an attribute of the service record
+ * of the SDP server itself. This attribute is guaranteed to
+ * change if any of the contents of the service repository
+ * changes. This function updates the timestamp of value of
+ * the svcDBState attribute
+ * Set the SDP server DB. Simply a timestamp which is the marker
+ * when the DB was modified.
+ */
+static void update_db_timestamp(void)
+{
+ uint32_t dbts = sdp_get_time();
+ sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts);
+ sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
+}
+
+static void update_svclass_list(void)
+{
+ sdp_list_t *list = sdp_get_record_list();
+ uint8_t val = 0;
+
+ for (; list; list = list->next) {
+ sdp_record_t *rec = (sdp_record_t *) list->data;
+
+ if (rec->svclass.type != SDP_UUID16)
+ continue;
+
+ switch (rec->svclass.value.uuid16) {
+ case DIALUP_NET_SVCLASS_ID:
+ case CIP_SVCLASS_ID:
+ val |= 0x42; /* Telephony & Networking */
+ break;
+ case IRMC_SYNC_SVCLASS_ID:
+ case OBEX_OBJPUSH_SVCLASS_ID:
+ case OBEX_FILETRANS_SVCLASS_ID:
+ case IRMC_SYNC_CMD_SVCLASS_ID:
+ case PBAP_PSE_SVCLASS_ID:
+ val |= 0x10; /* Object Transfer */
+ break;
+ case HEADSET_SVCLASS_ID:
+ case HANDSFREE_SVCLASS_ID:
+ val |= 0x20; /* Audio */
+ break;
+ case CORDLESS_TELEPHONY_SVCLASS_ID:
+ case INTERCOM_SVCLASS_ID:
+ case FAX_SVCLASS_ID:
+ case SAP_SVCLASS_ID:
+ val |= 0x40; /* Telephony */
+ break;
+ case AUDIO_SOURCE_SVCLASS_ID:
+ case VIDEO_SOURCE_SVCLASS_ID:
+ val |= 0x08; /* Capturing */
+ break;
+ case AUDIO_SINK_SVCLASS_ID:
+ case VIDEO_SINK_SVCLASS_ID:
+ val |= 0x04; /* Rendering */
+ break;
+ case PANU_SVCLASS_ID:
+ case NAP_SVCLASS_ID:
+ case GN_SVCLASS_ID:
+ val |= 0x02; /* Networking */
+ break;
+ }
+ }
+
+ debug("Service classes 0x%02x", val);
+
+ service_classes = val;
+
+ if (service_classes_callback)
+ service_classes_callback(BDADDR_ANY, val);
+}
+
+uint8_t get_service_classes(const bdaddr_t *bdaddr)
+{
+ return service_classes;
+}
+
+void set_service_classes_callback(service_classes_callback_t callback)
+{
+ service_classes_callback = callback;
+}
+
+void create_ext_inquiry_response(const char *name, uint8_t *data)
+{
+ sdp_list_t *list = sdp_get_record_list();
+ uint8_t *ptr = data;
+ uint16_t uuid[24];
+ int i, index = 0;
+
+ if (name) {
+ int len = strlen(name);
+
+ if (len > 48) {
+ len = 48;
+ ptr[1] = 0x08;
+ } else
+ ptr[1] = 0x09;
+
+ ptr[0] = len + 1;
+
+ memcpy(ptr + 2, name, len);
+
+ ptr += len + 2;
+ }
+
+ if (did_vendor != 0x0000) {
+ uint16_t source = 0x0002;
+ *ptr++ = 9;
+ *ptr++ = 11;
+ *ptr++ = (source & 0x00ff);
+ *ptr++ = (source & 0xff00) >> 8;
+ *ptr++ = (did_vendor & 0x00ff);
+ *ptr++ = (did_vendor & 0xff00) >> 8;
+ *ptr++ = (did_product & 0x00ff);
+ *ptr++ = (did_product & 0xff00) >> 8;
+ *ptr++ = (did_version & 0x00ff);
+ *ptr++ = (did_version & 0xff00) >> 8;
+ }
+
+ ptr[1] = 0x03;
+
+ for (; list; list = list->next) {
+ sdp_record_t *rec = (sdp_record_t *) list->data;
+
+ if (rec->svclass.type != SDP_UUID16)
+ continue;
+
+ if (rec->svclass.value.uuid16 < 0x1100)
+ continue;
+
+ if (index > 23) {
+ ptr[1] = 0x02;
+ break;
+ }
+
+ for (i = 0; i < index; i++)
+ if (uuid[i] == rec->svclass.value.uuid16)
+ break;
+
+ if (i == index - 1)
+ continue;
+
+ uuid[index++] = rec->svclass.value.uuid16;
+ }
+
+ if (index > 0) {
+ ptr[0] = (index * 2) + 1;
+ ptr += 2;
+
+ for (i = 0; i < index; i++) {
+ *ptr++ = (uuid[i] & 0x00ff);
+ *ptr++ = (uuid[i] & 0xff00) >> 8;
+ }
+ }
+}
+
+void register_public_browse_group(void)
+{
+ sdp_list_t *browselist;
+ uuid_t bgscid, pbgid;
+ sdp_data_t *sdpdata;
+ sdp_record_t *browse = sdp_record_alloc();
+
+ browse->handle = SDP_SERVER_RECORD_HANDLE + 1;
+
+ sdp_record_add(BDADDR_ANY, browse);
+ sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle);
+ sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata);
+
+ sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID);
+ browselist = sdp_list_append(0, &bgscid);
+ sdp_set_service_classes(browse, browselist);
+ sdp_list_free(browselist, 0);
+
+ sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
+ sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID,
+ SDP_UUID16, &pbgid.value.uuid16);
+}
+
+/*
+ * The SDP server must present its own service record to
+ * the service repository. This can be accessed by service
+ * discovery clients. This method constructs a service record
+ * and stores it in the repository
+ */
+void register_server_service(void)
+{
+ sdp_list_t *classIDList;
+ uuid_t classID;
+ void **versions, **versionDTDs;
+ uint8_t dtd;
+ sdp_data_t *pData;
+ int i;
+
+ server = sdp_record_alloc();
+ server->pattern = NULL;
+
+ /* Force the record to be SDP_SERVER_RECORD_HANDLE */
+ server->handle = SDP_SERVER_RECORD_HANDLE;
+
+ sdp_record_add(BDADDR_ANY, server);
+ sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE,
+ sdp_data_alloc(SDP_UINT32, &server->handle));
+
+ sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID);
+ classIDList = sdp_list_append(0, &classID);
+ sdp_set_service_classes(server, classIDList);
+ sdp_list_free(classIDList, 0);
+
+ /*
+ * Set the version numbers supported, these are passed as arguments
+ * to the server on command line. Now defaults to 1.0
+ * Build the version number sequence first
+ */
+ versions = (void **)malloc(sdpServerVnumEntries * sizeof(void *));
+ versionDTDs = (void **)malloc(sdpServerVnumEntries * sizeof(void *));
+ dtd = SDP_UINT16;
+ for (i = 0; i < sdpServerVnumEntries; i++) {
+ uint16_t *version = malloc(sizeof(uint16_t));
+ *version = sdpVnumArray[i].major;
+ *version = (*version << 8);
+ *version |= sdpVnumArray[i].minor;
+ versions[i] = version;
+ versionDTDs[i] = &dtd;
+ }
+ pData = sdp_seq_alloc(versionDTDs, versions, sdpServerVnumEntries);
+ for (i = 0; i < sdpServerVnumEntries; i++)
+ free(versions[i]);
+ free(versions);
+ free(versionDTDs);
+ sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData);
+
+ update_db_timestamp();
+ update_svclass_list();
+}
+
+void register_device_id(const uint16_t vendor, const uint16_t product,
+ const uint16_t version)
+{
+ const uint16_t spec = 0x0102, source = 0x0002;
+ const uint8_t primary = 1;
+ sdp_list_t *class_list, *group_list, *profile_list;
+ uuid_t class_uuid, group_uuid;
+ sdp_data_t *sdp_data, *primary_data, *source_data;
+ sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record = sdp_record_alloc();
+
+ info("Adding device id record for %04x:%04x", vendor, product);
+
+ did_vendor = vendor;
+ did_product = product;
+ did_version = version;
+
+ record->handle = sdp_next_handle();
+
+ sdp_record_add(BDADDR_ANY, record);
+ sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+ sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+ sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
+ class_list = sdp_list_append(0, &class_uuid);
+ sdp_set_service_classes(record, class_list);
+ sdp_list_free(class_list, NULL);
+
+ sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
+ group_list = sdp_list_append(NULL, &group_uuid);
+ sdp_set_browse_groups(record, group_list);
+ sdp_list_free(group_list, NULL);
+
+ sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
+ profile.version = spec;
+ profile_list = sdp_list_append(NULL, &profile);
+ sdp_set_profile_descs(record, profile_list);
+ sdp_list_free(profile_list, NULL);
+
+ spec_data = sdp_data_alloc(SDP_UINT16, &spec);
+ sdp_attr_add(record, 0x0200, spec_data);
+
+ vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
+ sdp_attr_add(record, 0x0201, vendor_data);
+
+ product_data = sdp_data_alloc(SDP_UINT16, &product);
+ sdp_attr_add(record, 0x0202, product_data);
+
+ version_data = sdp_data_alloc(SDP_UINT16, &version);
+ sdp_attr_add(record, 0x0203, version_data);
+
+ primary_data = sdp_data_alloc(SDP_BOOL, &primary);
+ sdp_attr_add(record, 0x0204, primary_data);
+
+ source_data = sdp_data_alloc(SDP_UINT16, &source);
+ sdp_attr_add(record, 0x0205, source_data);
+
+ update_db_timestamp();
+ update_svclass_list();
+}
+
+int add_record_to_server(bdaddr_t *src, sdp_record_t *rec)
+{
+ sdp_data_t *data;
+
+ if (rec->handle == 0xffffffff) {
+ rec->handle = sdp_next_handle();
+ if (rec->handle < 0x10000)
+ return -1;
+ } else {
+ if (sdp_record_find(rec->handle))
+ return -1;
+ }
+
+ debug("Adding record with handle 0x%05x", rec->handle);
+
+ sdp_record_add(src, rec);
+
+ data = sdp_data_alloc(SDP_UINT32, &rec->handle);
+ sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data);
+
+ if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
+ uuid_t uuid;
+ sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
+ sdp_pattern_add_uuid(rec, &uuid);
+ }
+
+ update_db_timestamp();
+ update_svclass_list();
+
+ return 0;
+}
+
+int remove_record_from_server(uint32_t handle)
+{
+ sdp_record_t *rec;
+
+ debug("Removing record with handle 0x%05x", handle);
+
+ rec = sdp_record_find(handle);
+ if (!rec)
+ return -ENOENT;
+
+ if (sdp_record_remove(handle) == 0) {
+ update_db_timestamp();
+ update_svclass_list();
+ }
+
+ sdp_record_free(rec);
+
+ return 0;
+}
+
+// FIXME: refactor for server-side
+static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p, int bufsize, uint32_t handleExpected, int *scanned)
+{
+ int extractStatus = -1, localExtractedLength = 0;
+ uint8_t dtd;
+ int seqlen = 0;
+ sdp_record_t *rec = NULL;
+ uint16_t attrId, lookAheadAttrId;
+ sdp_data_t *pAttr = NULL;
+ uint32_t handle = 0xffffffff;
+
+ *scanned = sdp_extract_seqtype_safe(p, bufsize, &dtd, &seqlen);
+ p += *scanned;
+ bufsize -= *scanned;
+
+ if (bufsize < sizeof(uint8_t) + sizeof(uint8_t)) {
+ debug("Unexpected end of packet");
+ return NULL;
+ }
+
+ lookAheadAttrId = ntohs(bt_get_unaligned((uint16_t *) (p + sizeof(uint8_t))));
+
+ debug("Look ahead attr id : %d", lookAheadAttrId);
+
+ if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) {
+ if (bufsize < (sizeof(uint8_t) * 2) + sizeof(uint16_t) + sizeof(uint32_t)) {
+ debug("Unexpected end of packet");
+ return NULL;
+ }
+ handle = ntohl(bt_get_unaligned((uint32_t *) (p +
+ sizeof(uint8_t) + sizeof(uint16_t) +
+ sizeof(uint8_t))));
+ debug("SvcRecHandle : 0x%x", handle);
+ rec = sdp_record_find(handle);
+ } else if (handleExpected != 0xffffffff)
+ rec = sdp_record_find(handleExpected);
+
+ if (!rec) {
+ rec = sdp_record_alloc();
+ rec->attrlist = NULL;
+ if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) {
+ rec->handle = handle;
+ sdp_record_add(device, rec);
+ } else if (handleExpected != 0xffffffff) {
+ rec->handle = handleExpected;
+ sdp_record_add(device, rec);
+ }
+ } else {
+ sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free);
+ rec->attrlist = NULL;
+ }
+
+ while (localExtractedLength < seqlen) {
+ int attrSize = sizeof(uint8_t);
+ int attrValueLength = 0;
+
+ if (bufsize < attrSize + sizeof(uint16_t)) {
+ debug("Unexpected end of packet: Terminating extraction of attributes");
+ break;
+ }
+
+ debug("Extract PDU, sequenceLength: %d localExtractedLength: %d", seqlen, localExtractedLength);
+ dtd = *(uint8_t *) p;
+
+ attrId = ntohs(bt_get_unaligned((uint16_t *) (p + attrSize)));
+ attrSize += sizeof(uint16_t);
+
+ debug("DTD of attrId : %d Attr id : 0x%x", dtd, attrId);
+
+ pAttr = sdp_extract_attr_safe(p + attrSize, bufsize - attrSize,
+ &attrValueLength, rec);
+
+ debug("Attr id : 0x%x attrValueLength : %d", attrId, attrValueLength);
+
+ attrSize += attrValueLength;
+ if (pAttr == NULL) {
+ debug("Terminating extraction of attributes");
+ break;
+ }
+ localExtractedLength += attrSize;
+ p += attrSize;
+ bufsize -= attrSize;
+ sdp_attr_replace(rec, attrId, pAttr);
+ extractStatus = 0;
+ debug("Extract PDU, seqLength: %d localExtractedLength: %d",
+ seqlen, localExtractedLength);
+ }
+
+ if (extractStatus == 0) {
+ debug("Successful extracting of Svc Rec attributes");
+#ifdef SDP_DEBUG
+ sdp_print_service_attr(rec->attrlist);
+#endif
+ *scanned += seqlen;
+ }
+ return rec;
+}
+
+/*
+ * Add the newly created service record to the service repository
+ */
+int service_register_req(sdp_req_t *req, sdp_buf_t *rsp)
+{
+ int scanned = 0;
+ sdp_data_t *handle;
+ uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
+ int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
+ sdp_record_t *rec;
+
+ req->flags = *p++;
+ if (req->flags & SDP_DEVICE_RECORD) {
+ bacpy(&req->device, (bdaddr_t *) p);
+ p += sizeof(bdaddr_t);
+ bufsize -= sizeof(bdaddr_t);
+ }
+
+ // save image of PDU: we need it when clients request this attribute
+ rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned);
+ if (!rec)
+ goto invalid;
+
+ if (rec->handle == 0xffffffff) {
+ rec->handle = sdp_next_handle();
+ if (rec->handle < 0x10000) {
+ sdp_record_free(rec);
+ goto invalid;
+ }
+ } else {
+ if (sdp_record_find(rec->handle)) {
+ sdp_record_free(rec);
+ goto invalid;
+ }
+ }
+
+ sdp_record_add(&req->device, rec);
+ if (!(req->flags & SDP_RECORD_PERSIST))
+ sdp_svcdb_set_collectable(rec, req->sock);
+
+ handle = sdp_data_alloc(SDP_UINT32, &rec->handle);
+ sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle);
+
+ /*
+ * if the browse group descriptor is NULL,
+ * ensure that the record belongs to the ROOT group
+ */
+ if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
+ uuid_t uuid;
+ sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
+ sdp_pattern_add_uuid(rec, &uuid);
+ }
+
+ update_db_timestamp();
+ update_svclass_list();
+
+ /* Build a rsp buffer */
+ bt_put_unaligned(htonl(rec->handle), (uint32_t *) rsp->data);
+ rsp->data_size = sizeof(uint32_t);
+
+ return 0;
+
+invalid:
+ bt_put_unaligned(htons(SDP_INVALID_SYNTAX), (uint16_t *) rsp->data);
+ rsp->data_size = sizeof(uint16_t);
+
+ return -1;
+}
+
+/*
+ * Update a service record
+ */
+int service_update_req(sdp_req_t *req, sdp_buf_t *rsp)
+{
+ sdp_record_t *orec;
+ int status = 0, scanned = 0;
+ uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
+ int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
+ uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
+
+ debug("Svc Rec Handle: 0x%x", handle);
+
+ p += sizeof(uint32_t);
+ bufsize -= sizeof(uint32_t);
+
+ orec = sdp_record_find(handle);
+
+ debug("SvcRecOld: %p", orec);
+
+ if (orec) {
+ sdp_record_t *nrec = extract_pdu_server(BDADDR_ANY, p, bufsize, handle, &scanned);
+ if (nrec && handle == nrec->handle) {
+ update_db_timestamp();
+ update_svclass_list();
+ } else {
+ debug("SvcRecHandle : 0x%x", handle);
+ debug("SvcRecHandleNew : 0x%x", nrec->handle);
+ debug("SvcRecNew : %p", nrec);
+ debug("SvcRecOld : %p", orec);
+ debug("Failure to update, restore old value");
+
+ if (nrec)
+ sdp_record_free(nrec);
+ status = SDP_INVALID_SYNTAX;
+ }
+ } else
+ status = SDP_INVALID_RECORD_HANDLE;
+
+ p = rsp->data;
+ bt_put_unaligned(htons(status), (uint16_t *) p);
+ rsp->data_size = sizeof(uint16_t);
+ return status;
+}
+
+/*
+ * Remove a registered service record
+ */
+int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
+{
+ uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
+ uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
+ sdp_record_t *rec;
+ int status = 0;
+
+ /* extract service record handle */
+ p += sizeof(uint32_t);
+
+ rec = sdp_record_find(handle);
+ if (rec) {
+ sdp_svcdb_collect(rec);
+ status = sdp_record_remove(handle);
+ sdp_record_free(rec);
+ if (status == 0) {
+ update_db_timestamp();
+ update_svclass_list();
+ }
+ } else {
+ status = SDP_INVALID_RECORD_HANDLE;
+ debug("Could not find record : 0x%x", handle);
+ }
+
+ p = rsp->data;
+ bt_put_unaligned(htons(status), (uint16_t *) p);
+ rsp->data_size = sizeof(uint16_t);
+
+ return status;
+}
diff --git a/utils/sdpd/servicedb.c b/utils/sdpd/servicedb.c
new file mode 100644
index 00000000..6cc34bd3
--- /dev/null
+++ b/utils/sdpd/servicedb.c
@@ -0,0 +1,304 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2002 Nokia Corporation
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "sdpd.h"
+#include "logging.h"
+
+static sdp_list_t *service_db;
+static sdp_list_t *access_db;
+
+typedef struct {
+ uint32_t handle;
+ bdaddr_t device;
+} sdp_access_t;
+
+/*
+ * Ordering function called when inserting a service record.
+ * 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)
+{
+ const sdp_record_t *rec1 = (const sdp_record_t *) r1;
+ const sdp_record_t *rec2 = (const sdp_record_t *) r2;
+
+ if (!rec1 || !rec2) {
+ error("NULL RECORD LIST FATAL");
+ return -1;
+ }
+
+ return rec1->handle - rec2->handle;
+}
+
+static int access_sort(const void *r1, const void *r2)
+{
+ const sdp_access_t *rec1 = (const sdp_access_t *) r1;
+ const sdp_access_t *rec2 = (const sdp_access_t *) r2;
+
+ if (!rec1 || !rec2) {
+ error("NULL RECORD LIST FATAL");
+ return -1;
+ }
+
+ return rec1->handle - rec2->handle;
+}
+
+static void access_free(void *p)
+{
+ free(p);
+}
+
+/*
+ * Reset the service repository by deleting its contents
+ */
+void sdp_svcdb_reset()
+{
+ sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free);
+ sdp_list_free(access_db, access_free);
+}
+
+typedef struct _indexed {
+ int sock;
+ sdp_record_t *record;
+} sdp_indexed_t;
+
+static sdp_list_t *socket_index;
+
+/*
+ * collect all services registered over this socket
+ */
+void sdp_svcdb_collect_all(int sock)
+{
+ sdp_list_t *p, *q;
+
+ for (p = socket_index, q = 0; p; ) {
+ sdp_indexed_t *item = (sdp_indexed_t *) p->data;
+ if (item->sock == sock) {
+ sdp_list_t *next = p->next;
+ sdp_record_remove(item->record->handle);
+ sdp_record_free(item->record);
+ free(item);
+ if (q)
+ q->next = next;
+ else
+ socket_index = next;
+ free(p);
+ p = next;
+ } else if (item->sock > sock)
+ return;
+ else {
+ q = p;
+ p = p->next;
+ }
+ }
+}
+
+void sdp_svcdb_collect(sdp_record_t *rec)
+{
+ sdp_list_t *p, *q;
+
+ for (p = socket_index, q = 0; p; q = p, p = p->next) {
+ sdp_indexed_t *item = (sdp_indexed_t *) p->data;
+ if (rec == item->record) {
+ free(item);
+ if (q)
+ q->next = p->next;
+ else
+ socket_index = p->next;
+ free(p);
+ return;
+ }
+ }
+}
+
+static int compare_indices(const void *i1, const void *i2)
+{
+ const sdp_indexed_t *s1 = (const sdp_indexed_t *) i1;
+ const sdp_indexed_t *s2 = (const sdp_indexed_t *) i2;
+ return s1->sock - s2->sock;
+}
+
+void sdp_svcdb_set_collectable(sdp_record_t *record, int sock)
+{
+ sdp_indexed_t *item = malloc(sizeof(sdp_indexed_t));
+ item->sock = sock;
+ item->record = record;
+ socket_index = sdp_list_insert_sorted(socket_index, item, compare_indices);
+}
+
+/*
+ * Add a service record to the repository
+ */
+void sdp_record_add(bdaddr_t *device, sdp_record_t *rec)
+{
+ sdp_access_t *dev;
+
+ debug("Adding rec : 0x%lx", (long) rec);
+ debug("with handle : 0x%x", rec->handle);
+
+ service_db = sdp_list_insert_sorted(service_db, rec, record_sort);
+
+ dev = malloc(sizeof(*dev));
+ if (!dev)
+ return;
+
+ bacpy(&dev->device, device);
+ dev->handle = rec->handle;
+
+ access_db = sdp_list_insert_sorted(access_db, dev, access_sort);
+}
+
+static sdp_list_t *record_locate(uint32_t handle)
+{
+ if (service_db) {
+ sdp_list_t *p;
+ sdp_record_t r;
+
+ r.handle = handle;
+ p = sdp_list_find(service_db, &r, record_sort);
+ return p;
+ }
+
+ debug("Could not find svcRec for : 0x%x", handle);
+ return NULL;
+}
+
+static sdp_list_t *access_locate(uint32_t handle)
+{
+ if (access_db) {
+ sdp_list_t *p;
+ sdp_access_t a;
+
+ a.handle = handle;
+ p = sdp_list_find(access_db, &a, access_sort);
+ return p;
+ }
+
+ debug("Could not find access data for : 0x%x", handle);
+ return NULL;
+}
+
+/*
+ * Given a service record handle, find the record associated with it.
+ */
+sdp_record_t *sdp_record_find(uint32_t handle)
+{
+ sdp_list_t *p = record_locate(handle);
+
+ if (!p) {
+ debug("Couldn't find record for : 0x%x", handle);
+ return 0;
+ }
+
+ return (sdp_record_t *) p->data;
+}
+
+/*
+ * Given a service record handle, remove its record from the repository
+ */
+int sdp_record_remove(uint32_t handle)
+{
+ sdp_list_t *p = record_locate(handle);
+ sdp_record_t *r;
+ sdp_access_t *a;
+
+ if (!p) {
+ error("Remove : Couldn't find record for : 0x%x", handle);
+ return -1;
+ }
+
+ r = (sdp_record_t *) p->data;
+ if (r)
+ service_db = sdp_list_remove(service_db, r);
+
+ p = access_locate(handle);
+ if (p) {
+ a = (sdp_access_t *) p->data;
+ if (a) {
+ access_db = sdp_list_remove(access_db, a);
+ access_free(a);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Return a pointer to the linked list containing the records in sorted order
+ */
+sdp_list_t *sdp_get_record_list(void)
+{
+ return service_db;
+}
+
+sdp_list_t *sdp_get_access_list(void)
+{
+ return access_db;
+}
+
+int sdp_check_access(uint32_t handle, bdaddr_t *device)
+{
+ sdp_list_t *p = access_locate(handle);
+ sdp_access_t *a;
+
+ if (!p)
+ return 1;
+
+ a = (sdp_access_t *) p->data;
+ if (!a)
+ return 1;
+
+ if (bacmp(&a->device, device) &&
+ bacmp(&a->device, BDADDR_ANY) &&
+ bacmp(device, BDADDR_ANY))
+ return 0;
+
+ return 1;
+}
+
+uint32_t sdp_next_handle(void)
+{
+ uint32_t handle = 0x10000;
+
+ while (sdp_record_find(handle))
+ handle++;
+
+ return handle;
+}
diff --git a/utils/serial/Makefile.am b/utils/serial/Makefile.am
new file mode 100644
index 00000000..0e6c47f7
--- /dev/null
+++ b/utils/serial/Makefile.am
@@ -0,0 +1,24 @@
+
+if SERIALPLUGIN
+plugindir = $(libdir)/bluetooth/plugins
+
+plugin_LTLIBRARIES = serial.la
+
+serial_la_SOURCES = main.c \
+ manager.h manager.c port.h port.c \
+ storage.h storage.c
+
+LDADD = $(top_builddir)/common/libhelper.a \
+ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+endif
+
+AM_LDFLAGS = -module -avoid-version -no-undefined \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -I$(top_srcdir)/sdpd
+
+EXTRA_DIST = serial-api.txt test-serial
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/serial/Makefile.in b/utils/serial/Makefile.in
new file mode 100644
index 00000000..88392a5a
--- /dev/null
+++ b/utils/serial/Makefile.in
@@ -0,0 +1,505 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = serial
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(plugindir)"
+pluginLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+serial_la_LIBADD =
+am__serial_la_SOURCES_DIST = main.c manager.h manager.c port.h port.c \
+ storage.h storage.c
+@SERIALPLUGIN_TRUE@am_serial_la_OBJECTS = main.lo manager.lo port.lo \
+@SERIALPLUGIN_TRUE@ storage.lo
+serial_la_OBJECTS = $(am_serial_la_OBJECTS)
+@SERIALPLUGIN_TRUE@am_serial_la_rpath = -rpath $(plugindir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(serial_la_SOURCES)
+DIST_SOURCES = $(am__serial_la_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@SERIALPLUGIN_TRUE@plugindir = $(libdir)/bluetooth/plugins
+@SERIALPLUGIN_TRUE@plugin_LTLIBRARIES = serial.la
+@SERIALPLUGIN_TRUE@serial_la_SOURCES = main.c \
+@SERIALPLUGIN_TRUE@ manager.h manager.c port.h port.c \
+@SERIALPLUGIN_TRUE@ storage.h storage.c
+
+@SERIALPLUGIN_TRUE@LDADD = $(top_builddir)/common/libhelper.a \
+@SERIALPLUGIN_TRUE@ @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
+
+AM_LDFLAGS = -module -avoid-version -no-undefined \
+ -export-symbols-regex bluetooth_plugin_desc
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/hcid -I$(top_srcdir)/sdpd
+EXTRA_DIST = serial-api.txt test-serial
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu serial/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu serial/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+serial.la: $(serial_la_OBJECTS) $(serial_la_DEPENDENCIES)
+ $(LINK) $(am_serial_la_rpath) $(serial_la_OBJECTS) $(serial_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/serial/main.c b/utils/serial/main.c
new file mode 100644
index 00000000..20aea93a
--- /dev/null
+++ b/utils/serial/main.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "device.h"
+#include "adapter.h"
+#include "logging.h"
+#include "manager.h"
+#include "port.h"
+
+#define SERIAL_PORT_UUID "00001101-0000-1000-8000-00805F9B34FB"
+#define DIALUP_NET_UUID "00001103-0000-1000-8000-00805F9B34FB"
+
+#define SERIAL_INTERFACE "org.bluez.Serial"
+#define ERROR_INVALID_ARGS "org.bluez.Error.InvalidArguments"
+#define ERROR_DOES_NOT_EXIST "org.bluez.Error.DoesNotExist"
+
+static DBusMessage *serial_connect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct btd_device *device = user_data;
+ const char *target;
+ char src[18], dst[18];
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &target,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ ba2str(&device->src, src);
+ ba2str(&device->dst, dst);
+
+ service_connect(conn, msg, src, dst, target);
+
+ return NULL;
+}
+
+static DBusMessage *serial_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ const char *device, *sender;
+ int err, id;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &device,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ sender = dbus_message_get_sender(msg);
+
+ if (sscanf(device, "/dev/rfcomm%d", &id) != 1)
+ return g_dbus_create_error(msg, ERROR_INVALID_ARGS, NULL);
+
+ err = port_remove_listener(sender, device);
+ if (err < 0)
+ return g_dbus_create_error(msg, ERROR_DOES_NOT_EXIST, NULL);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable serial_methods[] = {
+ { "Connect", "s", "s", serial_connect, G_DBUS_METHOD_FLAG_ASYNC },
+ { "Disconnect", "s", "", serial_disconnect },
+ { }
+};
+
+static DBusConnection *conn;
+
+static int serial_probe(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ if (g_dbus_register_interface(conn, device->path, SERIAL_INTERFACE,
+ serial_methods, NULL, NULL,
+ device, NULL) == FALSE)
+ return -1;
+
+ return 0;
+}
+
+static void serial_remove(struct btd_device *device)
+{
+ DBG("path %s", device->path);
+
+ g_dbus_unregister_interface(conn, device->path, SERIAL_INTERFACE);
+}
+
+static struct btd_device_driver serial_driver = {
+ .name = "serial",
+ .uuids = BTD_UUIDS(SERIAL_PORT_UUID, DIALUP_NET_UUID),
+ .probe = serial_probe,
+ .remove = serial_remove,
+};
+
+static int serial_init(void)
+{
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (conn == NULL)
+ return -EIO;
+
+ if (serial_manager_init(conn) < 0) {
+ dbus_connection_unref(conn);
+ return -EIO;
+ }
+
+ btd_register_device_driver(&serial_driver);
+
+ return 0;
+}
+
+static void serial_exit(void)
+{
+ btd_unregister_device_driver(&serial_driver);
+
+ serial_manager_exit();
+
+ dbus_connection_unref(conn);
+}
+
+BLUETOOTH_PLUGIN_DEFINE("serial", serial_init, serial_exit)
diff --git a/utils/serial/manager.c b/utils/serial/manager.c
new file mode 100644
index 00000000..442c386e
--- /dev/null
+++ b/utils/serial/manager.c
@@ -0,0 +1,1956 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/rfcomm.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "../hcid/dbus-common.h"
+
+#include "logging.h"
+#include "textfile.h"
+
+#include "error.h"
+#include "port.h"
+#include "storage.h"
+#include "manager.h"
+#include "sdpd.h"
+#include "glib-helper.h"
+
+#define SERIAL_PROXY_INTERFACE "org.bluez.serial.Proxy"
+#define BUF_SIZE 1024
+
+/* Waiting for udev to create the device node */
+#define MAX_OPEN_TRIES 5
+#define OPEN_WAIT 300 /* ms */
+
+struct pending_connect {
+ DBusConnection *conn;
+ DBusMessage *msg;
+ char *adapter; /* Adapter address */
+ char *address; /* Destination address */
+ char *pattern; /* Connection request pattern */
+ uint8_t channel;
+ char *dev; /* tty device name */
+ int id; /* RFCOMM device id */
+ int ntries; /* Open attempts */
+ int canceled; /* Operation canceled */
+ guint listener_id;
+};
+
+/* FIXME: Common file required */
+static struct {
+ const char *name;
+ uint16_t class;
+} serial_services[] = {
+ { "vcp", VIDEO_CONF_SVCLASS_ID },
+ { "pbap", PBAP_SVCLASS_ID },
+ { "sap", SAP_SVCLASS_ID },
+ { "ftp", OBEX_FILETRANS_SVCLASS_ID },
+ { "bpp", BASIC_PRINTING_SVCLASS_ID },
+ { "bip", IMAGING_SVCLASS_ID },
+ { "synch", IRMC_SYNC_SVCLASS_ID },
+ { "dun", DIALUP_NET_SVCLASS_ID },
+ { "opp", OBEX_OBJPUSH_SVCLASS_ID },
+ { "fax", FAX_SVCLASS_ID },
+ { "spp", SERIAL_PORT_SVCLASS_ID },
+ { NULL }
+};
+
+typedef enum {
+ TTY_PROXY,
+ UNIX_SOCKET_PROXY,
+ TCP_SOCKET_PROXY,
+ UNKNOWN_PROXY_TYPE = 0xFF
+} proxy_type_t;
+
+struct proxy {
+ bdaddr_t src;
+ bdaddr_t dst;
+ char *uuid128; /* UUID 128 */
+ char *address; /* TTY or Unix socket name */
+ char *path; /* D-Bus path */
+ short int port; /* TCP port */
+ proxy_type_t type; /* TTY or Unix socket */
+ struct termios sys_ti; /* Default TTY setting */
+ struct termios proxy_ti; /* Proxy TTY settings */
+ uint8_t channel; /* RFCOMM channel */
+ uint32_t record_id; /* Service record id */
+ GIOChannel *io; /* Server listen */
+ guint rfcomm_watch; /* RFCOMM watch: Remote */
+ guint local_watch; /* Local watch: TTY or Unix socket */
+};
+
+static DBusConnection *connection = NULL;
+static GSList *pending_connects = NULL;
+static GSList *ports_paths = NULL;
+static GSList *proxies = NULL;
+static int rfcomm_ctl = -1;
+static int sk_counter = 0;
+
+static void disable_proxy(struct proxy *prx)
+{
+ if (prx->rfcomm_watch) {
+ g_source_remove(prx->rfcomm_watch);
+ prx->rfcomm_watch = 0;
+ }
+
+ if (prx->local_watch) {
+ g_source_remove(prx->local_watch);
+ prx->local_watch = 0;
+ }
+
+ remove_record_from_server(prx->record_id);
+ prx->record_id = 0;
+
+ g_io_channel_unref(prx->io);
+ prx->io = NULL;
+}
+
+static void proxy_free(struct proxy *prx)
+{
+ g_free(prx->address);
+ g_free(prx->uuid128);
+ g_free(prx);
+}
+
+static void pending_connect_free(struct pending_connect *pc)
+{
+ if (pc->conn)
+ dbus_connection_unref(pc->conn);
+ if (pc->msg)
+ dbus_message_unref(pc->msg);
+ if (pc->adapter)
+ g_free(pc->adapter);
+ if (pc->address)
+ g_free(pc->address);
+ if (pc->pattern)
+ g_free(pc->pattern);
+ if (pc->dev)
+ g_free(pc->dev);
+ g_free(pc);
+}
+
+static struct pending_connect *find_pending_connect_by_pattern(const char *bda,
+ const char *pattern)
+{
+ GSList *l;
+
+ /* Pattern can be friendly name, uuid128, record handle or channel */
+ for (l = pending_connects; l != NULL; l = l->next) {
+ struct pending_connect *pending = l->data;
+ if (!strcasecmp(pending->address, bda) &&
+ !strcasecmp(pending->pattern, pattern))
+ return pending;
+ }
+
+ return NULL;
+}
+
+static void transaction_owner_exited(void *data)
+{
+ struct pending_connect *pc = data;
+
+ debug("transaction owner exited");
+
+ if (pc->id >= 0)
+ rfcomm_release(pc->id);
+
+ pending_connects = g_slist_remove(pending_connects, pc);
+
+ pending_connect_free(pc);
+}
+
+static void pending_connect_remove(struct pending_connect *pc)
+{
+ g_dbus_remove_watch(pc->conn, pc->listener_id);
+ pending_connects = g_slist_remove(pending_connects, pc);
+ pending_connect_free(pc);
+}
+
+static void open_notify(int fd, int err, struct pending_connect *pc)
+{
+ DBusMessage *reply;
+ bdaddr_t dst;
+
+ if (err) {
+ /* Max tries exceeded */
+ rfcomm_release(pc->id);
+ error_connection_attempt_failed(pc->conn, pc->msg, err);
+ return;
+ }
+
+ if (pc->canceled) {
+ rfcomm_release(pc->id);
+ error_canceled(pc->conn, pc->msg, "Connection canceled");
+ return;
+ }
+
+ /* Reply to the requestor */
+ reply = dbus_message_new_method_return(pc->msg);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &pc->dev,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(pc->conn, reply, NULL);
+ dbus_message_unref(reply);
+
+ /* Send the D-Bus signal */
+ g_dbus_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ServiceConnected" ,
+ DBUS_TYPE_STRING, &pc->dev,
+ DBUS_TYPE_INVALID);
+
+ str2ba(pc->address, &dst);
+
+ /* Add the RFCOMM connection listener */
+ port_add_listener(pc->conn, pc->id, &dst, fd,
+ pc->dev, dbus_message_get_sender(pc->msg));
+}
+
+static gboolean open_continue(struct pending_connect *pc)
+{
+ int fd;
+
+ if (!g_slist_find(pending_connects, pc))
+ return FALSE; /* Owner exited */
+
+ fd = open(pc->dev, O_RDONLY | O_NOCTTY);
+ if (fd < 0) {
+ int err = errno;
+ error("Could not open %s: %s (%d)",
+ pc->dev, strerror(err), err);
+ if (++pc->ntries >= MAX_OPEN_TRIES) {
+ /* Reporting error */
+ open_notify(fd, err, pc);
+ pending_connect_remove(pc);
+ return FALSE;
+ }
+ return TRUE;
+ }
+ /* Connection succeeded */
+ open_notify(fd, 0, pc);
+ pending_connect_remove(pc);
+ return FALSE;
+}
+
+int port_open(struct pending_connect *pc)
+{
+ int fd;
+
+ fd = open(pc->dev, O_RDONLY | O_NOCTTY);
+ if (fd < 0) {
+ g_timeout_add(OPEN_WAIT, (GSourceFunc) open_continue, pc);
+ return -EINPROGRESS;
+ }
+
+ return fd;
+}
+
+static uint16_t str2class(const char *pattern)
+{
+ int i;
+
+ for (i = 0; serial_services[i].name; i++) {
+ if (strcasecmp(serial_services[i].name, pattern) == 0)
+ return serial_services[i].class;
+ }
+
+ return 0;
+}
+
+int rfcomm_release(int16_t id)
+{
+ struct rfcomm_dev_req req;
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = id;
+
+ /*
+ * We are hitting a kernel bug inside RFCOMM code when
+ * RFCOMM_HANGUP_NOW bit is set on request's flags passed to
+ * ioctl(RFCOMMRELEASEDEV)!
+ */
+ req.flags = (1 << RFCOMM_HANGUP_NOW);
+
+ if (ioctl(rfcomm_ctl, RFCOMMRELEASEDEV, &req) < 0) {
+ int err = errno;
+ error("Can't release device %d: %s (%d)",
+ id, strerror(err), err);
+ return -err;
+ }
+
+ return 0;
+}
+
+static int rfcomm_bind(bdaddr_t *src, bdaddr_t *dst, int16_t dev_id, uint8_t ch)
+{
+ struct rfcomm_dev_req req;
+ int id;
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev_id;
+ req.flags = 0;
+ bacpy(&req.src, src);
+ bacpy(&req.dst, dst);
+ req.channel = ch;
+
+ id = ioctl(rfcomm_ctl, RFCOMMCREATEDEV, &req);
+ if (id < 0) {
+ int err = errno;
+ error("RFCOMMCREATEDEV failed: %s (%d)", strerror(err), err);
+ return -err;
+ }
+
+ return id;
+}
+
+static void rfcomm_connect_cb(GIOChannel *chan, int err_cb, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer user_data)
+{
+ struct pending_connect *pc = user_data;
+ struct rfcomm_dev_req req;
+ int sk, err, fd;
+
+ /* Owner exited? */
+ if (!g_slist_find(pending_connects, pc))
+ return;
+
+ if (pc->canceled) {
+ error_canceled(pc->conn, pc->msg, "Connection canceled");
+ goto fail;
+ }
+
+ if (err_cb < 0) {
+ error("connect(): %s (%d)", strerror(-err_cb), -err_cb);
+ error_connection_attempt_failed(pc->conn, pc->msg, -err_cb);
+ goto fail;
+ }
+
+ debug("rfcomm_connect_cb: connected");
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = -1;
+ req.flags = (1 << RFCOMM_REUSE_DLC);
+ str2ba(pc->adapter, &req.src);
+ str2ba(pc->address, &req.dst);
+ req.channel = pc->channel;
+
+ sk = g_io_channel_unix_get_fd(chan);
+ pc->id = ioctl(sk, RFCOMMCREATEDEV, &req);
+ g_io_channel_close(chan);
+ g_io_channel_unref(chan);
+ if (pc->id < 0) {
+ err = errno;
+ error("ioctl(RFCOMMCREATEDEV): %s (%d)", strerror(err), err);
+ error_connection_attempt_failed(pc->conn, pc->msg, err);
+ goto fail;
+ }
+ pc->dev = g_new0(char, 16);
+ snprintf(pc->dev, 16, "/dev/rfcomm%d", pc->id);
+
+ /* Addressing connect port */
+ fd = port_open(pc);
+ if (fd < 0)
+ /* Open in progress: Wait the callback */
+ return;
+
+ open_notify(fd, 0, pc);
+fail:
+ pending_connect_remove(pc);
+}
+
+static inline DBusMessage *does_not_exist(DBusMessage *msg,
+ const char *description)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist",
+ description);
+}
+
+static inline DBusMessage *invalid_arguments(DBusMessage *msg,
+ const char *description)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+ description);
+}
+
+static inline DBusMessage *failed(DBusMessage *msg, const char *description)
+{
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ description);
+}
+
+static DBusMessage *create_channel_port(DBusConnection *conn,
+ DBusMessage *msg, const char *adapter,
+ const char *address, const char *name,
+ long channel, void *data)
+{
+ char path[MAX_PATH_LENGTH], port_name[16];
+ const char *ppath = path;
+ DBusMessage *reply;
+ int err;
+ bdaddr_t src, dst;
+
+ if (channel < 1 || channel > 30)
+ return invalid_arguments(msg, "Invalid RFCOMM channel");
+
+ str2ba(adapter, &src);
+ str2ba(address, &dst);
+ err = rfcomm_bind(&src, &dst, -1, channel);
+ if (err < 0)
+ return failed(msg, strerror(-err));
+
+ snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", err);
+ port_store(&src, &dst, err, channel, name);
+ port_register(conn, err, &src, &dst, port_name, path, name);
+ ports_paths = g_slist_append(ports_paths, g_strdup(path));
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(conn, reply, NULL);
+ dbus_message_unref(reply);
+
+ g_dbus_emit_signal(conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "PortCreated" ,
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+
+ return NULL;
+}
+
+static DBusMessage *connect_pending(DBusConnection *conn, DBusMessage *msg,
+ struct pending_connect *pc)
+{
+ int err;
+ bdaddr_t src, dst;
+
+ if (!g_slist_find(pending_connects, pc)) {
+ pending_connects = g_slist_append(pending_connects, pc);
+ pc->listener_id = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ transaction_owner_exited, pc,
+ NULL);
+ }
+
+ str2ba(pc->adapter, &src);
+ str2ba(pc->address, &dst);
+
+ err = bt_rfcomm_connect(&src, &dst, pc->channel, rfcomm_connect_cb, pc);
+ if (err < 0) {
+ const char *strerr = strerror(-err);
+ error("RFCOMM connect failed: %s(%d)", strerr, -err);
+ pending_connects = g_slist_remove(pending_connects, pc);
+ pending_connect_free(pc);
+ return g_dbus_create_error(msg, ERROR_INTERFACE
+ ".ConnectionAttemptFailed",
+ "%s", strerror(-err));
+ }
+
+ return NULL;
+}
+
+static void record_cb(sdp_list_t *recs, int err, gpointer data)
+{
+ struct pending_connect *pc;
+ sdp_record_t *rec = NULL;
+ sdp_list_t *protos;
+ int ch;
+ bdaddr_t dst;
+
+ /* Owner exited? */
+ if (!g_slist_find(pending_connects, data))
+ return;
+
+ pc = data;
+ if (pc->canceled) {
+ error_canceled(pc->conn, pc->msg, "Connection canceled");
+ goto fail;
+ }
+
+ if (err < 0) {
+ error_connection_attempt_failed(pc->conn, pc->msg, -err);
+ goto fail;
+ }
+
+ if (!recs || !recs->data) {
+ error_not_supported(pc->conn, pc->msg);
+ error("Invalid service record length");
+ goto fail;
+ }
+
+ rec = recs->data;
+ if (sdp_get_access_protos(rec, &protos) < 0) {
+ error_not_supported(pc->conn, pc->msg);
+ goto fail;
+ }
+
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+
+ if (ch < 1 || ch > 30) {
+ error("Channel out of range: %d", ch);
+ error_not_supported(pc->conn, pc->msg);
+ goto fail;
+ }
+
+ str2ba(pc->address, &dst);
+
+ if (dbus_message_has_member(pc->msg, "CreatePort")) {
+ sdp_data_t *d;
+ char *svcname = NULL;
+
+ d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
+ if (d) {
+ svcname = g_new0(char, d->unitSize);
+ snprintf(svcname, d->unitSize, "%.*s",
+ d->unitSize, d->val.str);
+ }
+
+ create_channel_port(pc->conn, pc->msg, pc->adapter,
+ pc->address, svcname, ch, data);
+
+ if (svcname)
+ g_free(svcname);
+ } else {
+ /* ConnectService */
+ pc->channel = ch;
+
+ connect_pending(pc->conn, pc->msg, pc);
+
+ /* Wait the connect callback */
+ goto done;
+ }
+
+fail:
+ pending_connect_remove(pc);
+done:
+ if (recs)
+ sdp_list_free(recs, (sdp_free_func_t) sdp_record_free);
+}
+
+static int pattern2uuid(const char *pattern, uuid_t *uuid)
+{
+ uint16_t cls;
+ int i;
+
+ /* Friendly name */
+ cls = str2class(pattern);
+ if (cls) {
+ sdp_uuid16_create(uuid, cls);
+ return 0;
+ }
+
+ /* UUID 128*/
+ if (strlen(pattern) != 36)
+ return -EINVAL;
+
+ for (i = 0; i < 36; i++) {
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ if (pattern[i] != '-')
+ return -EINVAL;
+
+ } else if (!isxdigit(pattern[i]))
+ return -EINVAL;
+ }
+
+ bt_string2uuid(uuid, pattern);
+ return 0;
+}
+
+static int pattern2long(const char *pattern, long *pval)
+{
+ char *endptr;
+ long val;
+
+ errno = 0;
+ val = strtol(pattern, &endptr, 0);
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+ (errno != 0 && val == 0) || (pattern == endptr)) {
+ return -EINVAL;
+ }
+
+ *pval = val;
+
+ return 0;
+}
+
+static DBusMessage *search_uuid(DBusConnection *conn, DBusMessage *msg,
+ const char *adapter, const char *address,
+ const char *pattern, uuid_t *uuid, void *data)
+{
+ struct pending_connect *pc;
+ int err;
+ bdaddr_t src, dst;
+
+ pc = g_new0(struct pending_connect, 1);
+ pc->conn = dbus_connection_ref(conn);
+ pc->msg = dbus_message_ref(msg);
+ pc->adapter = g_strdup(adapter);
+ pc->address = g_strdup(address);
+ pc->id = -1;
+ pc->pattern = g_strdup(pattern);
+
+ str2ba(adapter, &src);
+ str2ba(address, &dst);
+
+ err = bt_search_service(&src, &dst, uuid, record_cb, pc, NULL);
+ if (err < 0) {
+ pending_connect_free(pc);
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotSuppported",
+ "Not Supported");
+ }
+
+ pending_connects = g_slist_append(pending_connects, pc);
+ pc->listener_id = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ transaction_owner_exited, pc, NULL);
+
+ return NULL;
+}
+
+static DBusMessage *create_port(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *address, *pattern;
+ struct pending_connect *pending;
+ long val;
+ uuid_t uuid;
+ char adp[18];
+ int dev_id;
+ bdaddr_t src;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ dev_id = hci_get_route(NULL);
+ if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
+ "Adapter not Available");
+
+ pending = find_pending_connect_by_pattern(address, pattern);
+ if (pending)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",
+ "Connection in Progress");
+
+ ba2str(&src, adp);
+
+ /* Friendly name or uuid128 */
+ if (pattern2uuid(pattern, &uuid) == 0)
+ return search_uuid(conn, msg, adp, address, pattern, &uuid,
+ data);
+
+ /* RFCOMM Channel */
+ if (pattern2long(pattern, &val) == 0)
+ return create_channel_port(conn, msg, adp, address, pattern,
+ val, data);
+
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArgument",
+ "Invalid pattern");
+}
+
+static void message_append_paths(DBusMessage *msg, const GSList *list)
+{
+ const GSList *l;
+ const char *path;
+ DBusMessageIter iter, iter_array;
+
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &iter_array);
+
+ for (l = list; l; l = l->next) {
+ path = l->data;
+ dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_STRING, &path);
+ }
+
+ dbus_message_iter_close_container(&iter, &iter_array);
+}
+
+static DBusMessage *list_ports(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ message_append_paths(reply, ports_paths);
+
+ return reply;
+}
+
+static DBusMessage *remove_port(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_dev_info di;
+ const char *path;
+ GSList *l;
+ int16_t id;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (sscanf(path, SERIAL_MANAGER_PATH"/rfcomm%hd", &id) != 1)
+ return does_not_exist(msg, "Invalid RFCOMM node");
+
+ di.id = id;
+ if (ioctl(rfcomm_ctl, RFCOMMGETDEVINFO, &di) < 0)
+ return does_not_exist(msg, "Invalid RFCOMM node");
+ port_delete(&di.src, &di.dst, id);
+
+ if (port_unregister(path) < 0)
+ return does_not_exist(msg, "Invalid RFCOMM node");
+
+ g_dbus_emit_signal(conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "PortRemoved" ,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ l = g_slist_find_custom(ports_paths, path, (GCompareFunc) strcmp);
+ if (l) {
+ g_free(l->data);
+ ports_paths = g_slist_remove(ports_paths, l->data);
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static void add_lang_attr(sdp_record_t *r)
+{
+ sdp_lang_attr_t base_lang;
+ sdp_list_t *langs = 0;
+
+ /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
+ base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
+ base_lang.encoding = 106;
+ base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
+ langs = sdp_list_append(0, &base_lang);
+ sdp_set_lang_attr(r, langs);
+ sdp_list_free(langs, 0);
+}
+
+static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel)
+{
+ sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
+ uuid_t uuid, root_uuid, l2cap, rfcomm;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_data_t *ch;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+ sdp_list_free(root, NULL);
+
+ bt_string2uuid(&uuid, uuid128);
+ svclass_id = sdp_list_append(NULL, &uuid);
+ sdp_set_service_classes(record, svclass_id);
+ sdp_list_free(svclass_id, NULL);
+
+ sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
+ profile.version = 0x0100;
+ profiles = sdp_list_append(NULL, &profile);
+ sdp_set_profile_descs(record, profiles);
+ sdp_list_free(profiles, NULL);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(NULL, &l2cap);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+ proto[1] = sdp_list_append(NULL, &rfcomm);
+ ch = sdp_data_alloc(SDP_UINT8, &channel);
+ proto[1] = sdp_list_append(proto[1], ch);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ add_lang_attr(record);
+
+ sdp_set_info_attr(record, "Port Proxy Entity",
+ NULL, "Port Proxy Entity");
+
+ sdp_data_free(ch);
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(proto[1], NULL);
+ sdp_list_free(apseq, NULL);
+ sdp_list_free(aproto, NULL);
+
+ return record;
+}
+
+static GIOError channel_write(GIOChannel *chan, char *buf, size_t size)
+{
+ GIOError err = G_IO_ERROR_NONE;
+ gsize wbytes, written;
+
+ wbytes = written = 0;
+ while (wbytes < size) {
+ err = g_io_channel_write(chan,
+ buf + wbytes,
+ size - wbytes,
+ &written);
+
+ if (err != G_IO_ERROR_NONE)
+ return err;
+
+ wbytes += written;
+ }
+
+ return err;
+}
+
+static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ char buf[BUF_SIZE];
+ GIOChannel *dest = data;
+ GIOError err;
+ size_t rbytes;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ /* Try forward remaining data */
+ do {
+ rbytes = 0;
+ err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes);
+ if (err != G_IO_ERROR_NONE || rbytes == 0)
+ break;
+
+ err = channel_write(dest, buf, rbytes);
+ } while (err == G_IO_ERROR_NONE);
+
+ g_io_channel_close(dest);
+ return FALSE;
+ }
+
+ rbytes = 0;
+ err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes);
+ if (err != G_IO_ERROR_NONE)
+ return FALSE;
+
+ err = channel_write(dest, buf, rbytes);
+ if (err != G_IO_ERROR_NONE)
+ return FALSE;
+
+ return TRUE;
+}
+
+static inline int unix_socket_connect(const char *address)
+{
+ struct sockaddr_un addr;
+ int err, sk;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = PF_UNIX;
+
+ if (strncmp("x00", address, 3) == 0) {
+ /*
+ * Abstract namespace: first byte NULL, x00
+ * must be removed from the original address.
+ */
+ strcpy(addr.sun_path + 1, address + 3);
+ } else {
+ /* Filesystem address */
+ strcpy(addr.sun_path, address);
+ }
+
+ /* Unix socket */
+ sk = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = errno;
+ error("Unix socket(%s) create failed: %s(%d)",
+ address, strerror(err), err);
+ return -err;
+ }
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ error("Unix socket(%s) connect failed: %s(%d)",
+ address, strerror(err), err);
+ close(sk);
+ errno = err;
+ return -err;
+ }
+
+ return sk;
+}
+
+static int tcp_socket_connect(const char *address)
+{
+ struct sockaddr_in addr;
+ int err, sk;
+ unsigned short int port;
+
+ memset(&addr, 0, sizeof(addr));
+
+ if (strncmp(address, "localhost", 9) != 0) {
+ error("Address should have the form localhost:port.");
+ return -1;
+ }
+ port = atoi(strchr(address, ':') + 1);
+ if (port <= 0) {
+ error("Invalid port '%d'.", port);
+ return -1;
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(port);
+
+ sk = socket(PF_INET, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = errno;
+ error("TCP socket(%s) create failed %s(%d)", address,
+ strerror(err), err);
+ return -err;
+ }
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ error("TCP socket(%s) connect failed: %s(%d)",
+ address, strerror(err), err);
+ close(sk);
+ errno = err;
+ return -err;
+ }
+ return sk;
+}
+
+static inline int tty_open(const char *tty, struct termios *ti)
+{
+ int err, sk;
+
+ sk = open(tty, O_RDWR | O_NOCTTY);
+ if (sk < 0) {
+ err = errno;
+ error("Can't open TTY %s: %s(%d)", tty, strerror(err), err);
+ return -err;
+ }
+
+ if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {
+ err = errno;
+ error("Can't change serial settings: %s(%d)",
+ strerror(err), err);
+ close(sk);
+ errno = err;
+ return -err;
+ }
+
+ return sk;
+}
+
+static void connect_event_cb(GIOChannel *chan, int err, const bdaddr_t *src,
+ const bdaddr_t *dst, gpointer data)
+{
+ struct proxy *prx = data;
+ GIOChannel *io;
+ int sk;
+
+ if (err < 0) {
+ error("accept: %s (%d)", strerror(-err), -err);
+ return;
+ }
+
+ bacpy(&prx->dst, dst);
+
+ switch (prx->type) {
+ case UNIX_SOCKET_PROXY:
+ sk = unix_socket_connect(prx->address);
+ break;
+ case TTY_PROXY:
+ sk = tty_open(prx->address, &prx->proxy_ti);
+ break;
+ case TCP_SOCKET_PROXY:
+ sk = tcp_socket_connect(prx->address);
+ break;
+ default:
+ sk = -1;
+ }
+
+ if (sk < 0) {
+ g_io_channel_unref(chan);
+ return;
+ }
+
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ prx->rfcomm_watch = g_io_add_watch(chan,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ forward_data, io);
+
+ prx->local_watch = g_io_add_watch(io,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ forward_data, chan);
+
+ g_io_channel_unref(chan);
+ g_io_channel_unref(io);
+
+ return;
+}
+
+static DBusMessage *proxy_enable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct proxy *prx = data;
+ sdp_record_t *record;
+
+ if (prx->io)
+ return failed(msg, "Already enabled");
+
+ /* Listen */
+ prx->io = bt_rfcomm_listen_allocate(&prx->src, &prx->channel, 0,
+ connect_event_cb, prx);
+ if (!prx->io) {
+ const char *strerr = strerror(errno);
+ error("RFCOMM listen socket failed: %s(%d)", strerr, errno);
+ return failed(msg, strerr);
+ }
+
+ g_io_channel_set_close_on_unref(prx->io, TRUE);
+
+ record = proxy_record_new(prx->uuid128, prx->channel);
+ if (!record) {
+ g_io_channel_unref(prx->io);
+ return failed(msg, "Unable to allocate new service record");
+ }
+
+ if (add_record_to_server(&prx->src, record) < 0) {
+ sdp_record_free(record);
+ g_io_channel_unref(prx->io);
+ return failed(msg, "Service registration failed");
+ }
+
+ prx->record_id = record->handle;
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *proxy_disable(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct proxy *prx = data;
+
+ if (!prx->io)
+ return failed(msg, "Not enabled");
+
+ /* Remove the watches and unregister the record */
+ disable_proxy(prx);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *proxy_get_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct proxy *prx = data;
+ DBusMessage *reply;
+ DBusMessageIter iter, dict;
+ dbus_bool_t boolean;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dbus_message_iter_append_dict_entry(&dict, "uuid",
+ DBUS_TYPE_STRING, &prx->uuid128);
+
+ dbus_message_iter_append_dict_entry(&dict, "address",
+ DBUS_TYPE_STRING, &prx->address);
+
+ if (prx->channel)
+ dbus_message_iter_append_dict_entry(&dict, "channel",
+ DBUS_TYPE_BYTE, &prx->channel);
+
+ boolean = (prx->io ? TRUE : FALSE);
+ dbus_message_iter_append_dict_entry(&dict, "enabled",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ boolean = (prx->rfcomm_watch ? TRUE : FALSE);
+ dbus_message_iter_append_dict_entry(&dict, "connected",
+ DBUS_TYPE_BOOLEAN, &boolean);
+
+ /* If connected: append the remote address */
+ if (boolean) {
+ char bda[18];
+ const char *pstr = bda;
+
+ ba2str(&prx->dst, bda);
+ dbus_message_iter_append_dict_entry(&dict, "address",
+ DBUS_TYPE_STRING, &pstr);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static struct {
+ const char *str;
+ speed_t speed;
+} supported_speed[] = {
+ {"50", B50 },
+ {"300", B300 },
+ {"600", B600 },
+ {"1200", B1200 },
+ {"1800", B1800 },
+ {"2400", B2400 },
+ {"4800", B4800 },
+ {"9600", B9600 },
+ {"19200", B19200 },
+ {"38400", B38400 },
+ {"57600", B57600 },
+ {"115200", B115200 },
+ { NULL, B0 }
+};
+
+static speed_t str2speed(const char *str, speed_t *speed)
+{
+ int i;
+
+ for (i = 0; supported_speed[i].str; i++) {
+ if (strcmp(supported_speed[i].str, str) != 0)
+ continue;
+
+ if (speed)
+ *speed = supported_speed[i].speed;
+
+ return supported_speed[i].speed;
+ }
+
+ return B0;
+}
+
+static int set_parity(const char *str, tcflag_t *ctrl)
+{
+ if (strcasecmp("even", str) == 0) {
+ *ctrl |= PARENB;
+ *ctrl &= ~PARODD;
+ } else if (strcasecmp("odd", str) == 0) {
+ *ctrl |= PARENB;
+ *ctrl |= PARODD;
+ } else if (strcasecmp("mark", str) == 0)
+ *ctrl |= PARENB;
+ else if ((strcasecmp("none", str) == 0) ||
+ (strcasecmp("space", str) == 0))
+ *ctrl &= ~PARENB;
+ else
+ return -1;
+
+ return 0;
+}
+
+static int set_databits(uint8_t databits, tcflag_t *ctrl)
+{
+ if (databits < 5 || databits > 8)
+ return -EINVAL;
+
+ *ctrl &= ~CSIZE;
+ switch (databits) {
+ case 5:
+ *ctrl |= CS5;
+ break;
+ case 6:
+ *ctrl |= CS6;
+ break;
+ case 7:
+ *ctrl |= CS7;
+ break;
+ case 8:
+ *ctrl |= CS8;
+ break;
+ }
+
+ return 0;
+}
+
+static int set_stopbits(uint8_t stopbits, tcflag_t *ctrl)
+{
+ /* 1.5 will not be allowed */
+ switch (stopbits) {
+ case 1:
+ *ctrl &= ~CSTOPB;
+ return 0;
+ case 2:
+ *ctrl |= CSTOPB;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static DBusMessage *proxy_set_serial_params(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct proxy *prx = data;
+ const char *ratestr, *paritystr;
+ uint8_t databits, stopbits;
+ tcflag_t ctrl; /* Control mode flags */
+ speed_t speed = B0; /* In/Out speed */
+
+ /* Don't allow change TTY settings if it is open */
+ if (prx->local_watch)
+ return failed(msg, "Not allowed");
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &ratestr,
+ DBUS_TYPE_BYTE, &databits,
+ DBUS_TYPE_BYTE, &stopbits,
+ DBUS_TYPE_STRING, &paritystr,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (str2speed(ratestr, &speed) == B0)
+ return invalid_arguments(msg, "Invalid baud rate");
+
+ ctrl = prx->proxy_ti.c_cflag;
+ if (set_databits(databits, &ctrl) < 0)
+ return invalid_arguments(msg, "Invalid data bits");
+
+ if (set_stopbits(stopbits, &ctrl) < 0)
+ return invalid_arguments(msg, "Invalid stop bits");
+
+ if (set_parity(paritystr, &ctrl) < 0)
+ return invalid_arguments(msg, "Invalid parity");
+
+ prx->proxy_ti.c_cflag = ctrl;
+ prx->proxy_ti.c_cflag |= (CLOCAL | CREAD);
+ cfsetispeed(&prx->proxy_ti, speed);
+ cfsetospeed(&prx->proxy_ti, speed);
+
+ proxy_store(&prx->src, prx->uuid128, prx->address, NULL,
+ prx->channel, 0, &prx->proxy_ti);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable proxy_methods[] = {
+ { "Enable", "", "", proxy_enable },
+ { "Disable", "", "", proxy_disable },
+ { "GetInfo", "", "a{sv}",proxy_get_info },
+ { "SetSerialParameters", "syys", "", proxy_set_serial_params },
+ { },
+};
+
+static void proxy_unregister(gpointer data)
+{
+ struct proxy *prx = data;
+ int sk;
+
+ info("Unregistered proxy: %s", prx->address);
+
+ if (prx->type != TTY_PROXY)
+ goto done;
+
+ /* Restore the initial TTY configuration */
+ sk = open(prx->address, O_RDWR | O_NOCTTY);
+ if (sk) {
+ tcsetattr(sk, TCSAFLUSH, &prx->sys_ti);
+ close(sk);
+ }
+done:
+
+ proxy_free(prx);
+}
+
+static int register_proxy_object(struct proxy *prx, char *outpath, size_t size)
+{
+ char path[MAX_PATH_LENGTH + 1];
+
+ snprintf(path, MAX_PATH_LENGTH, "/org/bluez/serial/proxy%d",
+ sk_counter++);
+
+ if (!g_dbus_register_interface(connection, path,
+ SERIAL_PROXY_INTERFACE,
+ proxy_methods, NULL, NULL,
+ prx, proxy_unregister)) {
+ error("D-Bus failed to register %s path", path);
+ return -1;
+ }
+
+ prx->path = g_strdup(path);
+ proxies = g_slist_append(proxies, prx);
+
+ if (outpath)
+ strncpy(outpath, path, size);
+
+ info("Registered proxy:%s", path);
+
+ return 0;
+}
+
+static int proxy_tty_register(bdaddr_t *src, const char *uuid128,
+ const char *address, struct termios *ti,
+ char *outpath, size_t size, gboolean save)
+{
+ struct termios sys_ti;
+ struct proxy *prx;
+ int sk, ret;
+
+ sk = open(address, O_RDONLY | O_NOCTTY);
+ if (sk < 0) {
+ error("Cant open TTY: %s(%d)", strerror(errno), errno);
+ return -EINVAL;
+ }
+
+ prx = g_new0(struct proxy, 1);
+ prx->address = g_strdup(address);
+ prx->uuid128 = g_strdup(uuid128);
+ prx->type = TTY_PROXY;
+ bacpy(&prx->src, src);
+
+ /* Current TTY settings */
+ memset(&sys_ti, 0, sizeof(sys_ti));
+ tcgetattr(sk, &sys_ti);
+ memcpy(&prx->sys_ti, &sys_ti, sizeof(sys_ti));
+ close(sk);
+
+ if (!ti) {
+ /* Use current settings */
+ memcpy(&prx->proxy_ti, &sys_ti, sizeof(sys_ti));
+ } else {
+ /* New TTY settings: user provided */
+ memcpy(&prx->proxy_ti, ti, sizeof(*ti));
+ }
+
+ ret = register_proxy_object(prx, outpath, size);
+ if (ret < 0)
+ proxy_free(prx);
+
+ if (save)
+ proxy_store(src, uuid128, address, NULL,
+ prx->channel, 0, &prx->proxy_ti);
+
+ return ret;
+}
+
+static int proxy_socket_register(bdaddr_t *src, const char *uuid128,
+ const char *address, char *outpath,
+ size_t size, gboolean save)
+{
+ struct proxy *prx;
+ int ret;
+
+ prx = g_new0(struct proxy, 1);
+ prx->address = g_strdup(address);
+ prx->uuid128 = g_strdup(uuid128);
+ prx->type = UNIX_SOCKET_PROXY;
+ bacpy(&prx->src, src);
+
+ ret = register_proxy_object(prx, outpath, size);
+ if (ret < 0)
+ proxy_free(prx);
+
+ if (save)
+ proxy_store(src, uuid128, address, NULL,
+ prx->channel, 0, NULL);
+
+ return ret;
+}
+
+static int proxy_tcp_register(bdaddr_t *src, const char *uuid128,
+ const char *address, char *outpath,
+ size_t size, gboolean save)
+{
+ struct proxy *prx;
+ int ret;
+
+ prx = g_new0(struct proxy, 1);
+ prx->address = g_strdup(address);
+ prx->uuid128 = g_strdup(uuid128);
+ prx->type = TCP_SOCKET_PROXY;
+ bacpy(&prx->src, src);
+
+ ret = register_proxy_object(prx, outpath, size);
+ if (ret < 0)
+ proxy_free(prx);
+
+ if (save)
+ proxy_store(src, uuid128, address, NULL,
+ prx->channel, 0, NULL);
+
+ return ret;
+}
+
+static proxy_type_t addr2type(const char *address)
+{
+ struct stat st;
+
+ if (stat(address, &st) < 0) {
+ /*
+ * Unix socket: if the sun_path starts with null byte
+ * it refers to abstract namespace. 'x00' will be used
+ * to represent the null byte.
+ */
+ if (strncmp("localhost:", address, 10) == 0)
+ return TCP_SOCKET_PROXY;
+ if (strncmp("x00", address, 3) != 0)
+ return UNKNOWN_PROXY_TYPE;
+ else
+ return UNIX_SOCKET_PROXY;
+ } else {
+ /* Filesystem: char device or unix socket */
+ if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0)
+ return TTY_PROXY;
+ else if (S_ISSOCK(st.st_mode))
+ return UNIX_SOCKET_PROXY;
+ else
+ return UNKNOWN_PROXY_TYPE;
+ }
+}
+
+static int proxy_addrcmp(gconstpointer proxy, gconstpointer addr)
+{
+ const struct proxy *prx = proxy;
+ const char *address = addr;
+
+ return strcmp(prx->address, address);
+}
+
+static int proxy_pathcmp(gconstpointer proxy, gconstpointer p)
+{
+ const struct proxy *prx = proxy;
+ const char *path = p;
+
+ return strcmp(prx->path, path);
+}
+
+static DBusMessage *create_proxy(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ char path[MAX_PATH_LENGTH + 1];
+ const char *uuid128, *address, *ppath = path;
+ DBusMessage *reply;
+ proxy_type_t type;
+ bdaddr_t src;
+ uuid_t uuid;
+ int dev_id, ret;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &uuid128,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (bt_string2uuid(&uuid, uuid128) < 0)
+ return invalid_arguments(msg, "Invalid UUID");
+
+ type = addr2type(address);
+ if (type == UNKNOWN_PROXY_TYPE)
+ return invalid_arguments(msg, "Invalid address");
+
+ /* Only one proxy per address(TTY or unix socket) is allowed */
+ if (g_slist_find_custom(proxies, address, proxy_addrcmp))
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExist",
+ "Proxy already exists");
+
+ dev_id = hci_get_route(NULL);
+ if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) {
+ error("Adapter not available");
+ return failed(msg, "Adapter no available");
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ switch (type) {
+ case UNIX_SOCKET_PROXY:
+ ret = proxy_socket_register(&src, uuid128, address,
+ path, sizeof(path), TRUE);
+ break;
+ case TTY_PROXY:
+ ret = proxy_tty_register(&src, uuid128, address,
+ NULL, path, sizeof(path), TRUE);
+ break;
+ case TCP_SOCKET_PROXY:
+ ret = proxy_tcp_register(&src, uuid128, address,
+ path, sizeof(path), TRUE);
+ break;
+ default:
+ ret = -1;
+ }
+ if (ret < 0) {
+ dbus_message_unref(reply);
+ return failed(msg, "Create object path failed");
+ }
+
+ g_dbus_emit_signal(connection, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ProxyCreated",
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *list_proxies(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct proxy *prx;
+ const GSList *l;
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &iter_array);
+
+ for (l = proxies; l; l = l->next) {
+ prx = l->data;
+ dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_STRING, &prx->path);
+ }
+
+ dbus_message_iter_close_container(&iter, &iter_array);
+
+ return reply;
+}
+
+static DBusMessage *remove_proxy(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct proxy *prx;
+ const char *path;
+ GSList *l;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ l = g_slist_find_custom(proxies, path, proxy_pathcmp);
+ if (!l)
+ return does_not_exist(msg, "Invalid proxy path");
+
+ g_dbus_emit_signal(conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ProxyRemoved",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ prx = l->data;
+ proxy_delete(&prx->src, prx->address);
+ proxies = g_slist_remove(proxies, prx);
+
+ g_dbus_unregister_interface(conn, path, SERIAL_PROXY_INTERFACE);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *connect_channel(DBusConnection *conn, DBusMessage *msg,
+ const char *adapter, const char *address,
+ const char *pattern, long channel, void *data)
+{
+ struct pending_connect *pc;
+
+ if (channel < 1 || channel > 30)
+ return invalid_arguments(msg, "Invalid RFCOMM channel");
+
+ pc = g_new0(struct pending_connect, 1);
+ pc->conn = dbus_connection_ref(conn);
+ pc->msg = dbus_message_ref(msg);
+ pc->adapter = g_strdup(adapter);
+ pc->address = g_strdup(address);
+ pc->id = -1;
+ pc->pattern = g_strdup(pattern);
+ pc->channel = channel;
+
+ return connect_pending(conn, msg, pc);
+}
+
+DBusMessage *service_connect(DBusConnection *conn, DBusMessage *msg,
+ const char *adapter,
+ const char *address,
+ const char *pattern)
+{
+ int dev_id;
+ bdaddr_t src;
+ char adp[18];
+ uuid_t uuid;
+ long val;
+
+ if (!adapter)
+ dev_id = hci_get_route(NULL);
+ else
+ dev_id = hci_devid(adapter);
+
+ if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
+ return failed(msg, "Adapter not Available");
+
+ ba2str(&src, adp);
+
+ /* Friendly name or uuid128 */
+ if (pattern2uuid(pattern, &uuid) == 0)
+ return search_uuid(conn, msg, adp, address,
+ pattern, &uuid, NULL);
+
+ /* RFCOMM Channel */
+ if (pattern2long(pattern, &val) == 0)
+ return connect_channel(conn, msg, adp, address,
+ pattern, val, NULL);
+
+ return invalid_arguments(msg, "Invalid Pattern");
+}
+
+static DBusMessage *connect_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *address, *pattern;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ return service_connect(conn, msg, NULL, address, pattern);
+}
+
+static DBusMessage *connect_service_from_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *adapter, *address, *pattern;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ return service_connect(conn, msg, adapter, address, pattern);
+}
+
+static DBusMessage *disconnect_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *name;
+ int err, id;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ if (sscanf(name, "/dev/rfcomm%d", &id) != 1)
+ return invalid_arguments(msg, "Invalid RFCOMM node");
+
+ err = port_remove_listener(dbus_message_get_sender(msg), name);
+ if (err < 0)
+ return does_not_exist(msg, "Invalid RFCOMM node");
+
+ g_dbus_emit_signal(conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *cancel_connect_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct pending_connect *pending;
+ const char *bda, *pattern;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &bda,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID))
+ return NULL;
+
+ pending = find_pending_connect_by_pattern(bda, pattern);
+ if (!pending)
+ return does_not_exist(msg, "No such connection request");
+
+ pending->canceled = 1;
+
+ return dbus_message_new_method_return(msg);
+}
+
+static void manager_unregister(void *data)
+{
+ if (pending_connects) {
+ g_slist_foreach(pending_connects,
+ (GFunc) pending_connect_free, NULL);
+ g_slist_free(pending_connects);
+ pending_connects = NULL;
+ }
+
+ if (proxies) {
+ g_slist_foreach(proxies,
+ (GFunc) proxy_unregister, NULL);
+ g_slist_free(proxies);
+ proxies = NULL;
+ }
+
+ if (ports_paths) {
+ g_slist_foreach(ports_paths,
+ (GFunc) g_free, NULL);
+ g_slist_free(ports_paths);
+ ports_paths = NULL;
+ }
+}
+
+static GDBusMethodTable manager_methods[] = {
+ { "CreatePort", "ss", "s", create_port,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "ListPorts", "", "as", list_ports },
+ { "RemovePort", "s", "", remove_port },
+ { "CreateProxy", "ss", "s", create_proxy },
+ { "ListProxies", "", "as", list_proxies },
+ { "RemoveProxy", "s", "", remove_proxy },
+ { "ConnectService", "ss", "s", connect_service,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "ConnectServiceFromAdapter", "sss", "s", connect_service_from_adapter,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "DisconnectService", "s", "", disconnect_service },
+ { "CancelConnectService", "ss", "", cancel_connect_service },
+ { },
+};
+
+static GDBusSignalTable manager_signals[] = {
+ { "PortCreated", "s" },
+ { "PortRemoved", "s" },
+ { "ProxyCreated", "s" },
+ { "ProxyRemoved", "s" },
+ { "ServiceConnected", "s" },
+ { "ServiceDisconnected", "s" },
+ { }
+};
+
+static void parse_port(char *key, char *value, void *data)
+{
+ char path[MAX_PATH_LENGTH], port_name[16], dst_addr[18], *svc;
+ char *src_addr = data;
+ bdaddr_t dst, src;
+ int ch, id;
+
+ memset(dst_addr, 0, sizeof(dst_addr));
+ if (sscanf(key,"%17s#%d", dst_addr, &id) != 2)
+ return;
+
+ if (sscanf(value,"%d:", &ch) != 1)
+ return;
+
+ svc = strchr(value, ':');
+ if (svc && *svc)
+ svc++;
+
+ str2ba(dst_addr, &dst);
+ str2ba(src_addr, &src);
+
+ if (rfcomm_bind(&src, &dst, id, ch) < 0)
+ return;
+
+ snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", id);
+
+ if (port_register(connection, id, &src, &dst,
+ port_name, path, svc) < 0) {
+ rfcomm_release(id);
+ return;
+ }
+
+ ports_paths = g_slist_append(ports_paths, g_strdup(path));
+}
+
+static void parse_proxy(char *key, char *value, void *data)
+{
+ char uuid128[MAX_LEN_UUID_STR], tmp[3];
+ char *pvalue, *src_addr = data;
+ proxy_type_t type;
+ int ch, opts, pos;
+ bdaddr_t src;
+ struct termios ti;
+ uint8_t *pti;
+
+ memset(uuid128, 0, sizeof(uuid128));
+ ch = opts = pos = 0;
+ if (sscanf(value,"%s %d 0x%04X %n", uuid128, &ch, &opts, &pos) != 3)
+ return;
+
+ /* Extracting name */
+ value += pos;
+ pvalue = strchr(value, ':');
+ if (!pvalue)
+ return;
+
+ /* FIXME: currently name is not used */
+ *pvalue = '\0';
+
+ str2ba(src_addr, &src);
+ type = addr2type(key);
+ switch (type) {
+ case TTY_PROXY:
+ /* Extracting termios */
+ pvalue++;
+ if (!pvalue || strlen(pvalue) != (2 * sizeof(ti)))
+ return;
+
+ memset(&ti, 0, sizeof(ti));
+ memset(tmp, 0, sizeof(tmp));
+
+ /* Converting to termios struct */
+ pti = (uint8_t *) &ti;
+ for (pos = 0; pos < sizeof(ti); pos++, pvalue += 2, pti++) {
+ memcpy(tmp, pvalue, 2);
+ *pti = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ proxy_tty_register(&src, uuid128, key, &ti, NULL, 0, FALSE);
+ break;
+ case UNIX_SOCKET_PROXY:
+ proxy_socket_register(&src, uuid128, key, NULL, 0, FALSE);
+ break;
+ case TCP_SOCKET_PROXY:
+ proxy_tcp_register(&src, uuid128, key, NULL, 0, FALSE);
+ break;
+ default:
+ return;
+ }
+}
+
+static void register_stored(void)
+{
+ char filename[PATH_MAX + 1];
+ struct dirent *de;
+ DIR *dir;
+
+ snprintf(filename, PATH_MAX, "%s", STORAGEDIR);
+
+ dir = opendir(filename);
+ if (!dir)
+ return;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (!isdigit(de->d_name[0]))
+ continue;
+
+ snprintf(filename, PATH_MAX, "%s/%s/serial", STORAGEDIR, de->d_name);
+ textfile_foreach(filename, parse_port, de->d_name);
+
+ snprintf(filename, PATH_MAX, "%s/%s/proxy", STORAGEDIR, de->d_name);
+ textfile_foreach(filename, parse_proxy, de->d_name);
+ }
+
+ closedir(dir);
+}
+
+int serial_manager_init(DBusConnection *conn)
+{
+
+ if (rfcomm_ctl < 0) {
+ rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
+ if (rfcomm_ctl < 0)
+ return -errno;
+ }
+
+ if (!g_dbus_register_interface(conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE,
+ manager_methods, manager_signals, NULL,
+ NULL, manager_unregister)) {
+ error("Failed to register %s interface to %s",
+ SERIAL_MANAGER_INTERFACE, SERIAL_MANAGER_PATH);
+ return -1;
+ }
+
+ connection = dbus_connection_ref(conn);
+
+ info("Registered manager path:%s", SERIAL_MANAGER_PATH);
+
+ register_stored();
+
+ return 0;
+}
+
+void serial_manager_exit(void)
+{
+ g_dbus_unregister_interface(connection, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+
+ port_release_all();
+
+ if (rfcomm_ctl >= 0)
+ close(rfcomm_ctl);
+}
diff --git a/utils/serial/manager.h b/utils/serial/manager.h
new file mode 100644
index 00000000..fdcc8ab9
--- /dev/null
+++ b/utils/serial/manager.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define SERIAL_MANAGER_PATH "/org/bluez/serial"
+#define SERIAL_MANAGER_INTERFACE "org.bluez.serial.Manager"
+
+int serial_manager_init(DBusConnection *conn);
+void serial_manager_exit(void);
+int rfcomm_release(int16_t id);
+
+DBusMessage *service_connect(DBusConnection *conn, DBusMessage *msg,
+ const char *adapter,
+ const char *address,
+ const char *pattern);
diff --git a/utils/serial/port.c b/utils/serial/port.c
new file mode 100644
index 00000000..f0563244
--- /dev/null
+++ b/utils/serial/port.c
@@ -0,0 +1,404 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "../hcid/dbus-common.h"
+
+#include "logging.h"
+
+#include "error.h"
+#include "manager.h"
+#include "storage.h"
+
+#define SERIAL_PORT_INTERFACE "org.bluez.serial.Port"
+
+struct rfcomm_node {
+ int16_t id; /* RFCOMM device id */
+ bdaddr_t src; /* Source (local) address */
+ bdaddr_t dst; /* Destination address */
+ char *svcname; /* RFCOMM service name */
+ char *device; /* RFCOMM device name */
+ DBusConnection *conn; /* for name listener handling */
+ char *owner; /* Bus name */
+ GIOChannel *io; /* Connected node IO Channel */
+ guint io_id; /* IO Channel ID */
+ guint listener_id;
+};
+
+static GSList *connected_nodes = NULL;
+static GSList *bound_nodes = NULL;
+
+static struct rfcomm_node *find_node_by_name(GSList *nodes, const char *dev)
+{
+ GSList *l;
+
+ for (l = nodes; l != NULL; l = l->next) {
+ struct rfcomm_node *node = l->data;
+ if (!strcmp(node->device, dev))
+ return node;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *port_get_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+ char bda[18];
+ const char *pbda = bda;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ ba2str(&node->dst, bda);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &pbda,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *port_get_device(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &node->device,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+
+}
+
+static DBusMessage *port_get_adapter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+ char addr[18];
+ const char *paddr = addr;
+
+ ba2str(&node->src, addr);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &paddr,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+
+static DBusMessage *port_get_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+ const char *pname;
+ char *name = NULL;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ read_device_name(&node->src, &node->dst, &name);
+
+ pname = (name ? name : "");
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &pname,
+ DBUS_TYPE_INVALID);
+
+ if (name)
+ g_free(name);
+
+ return reply;
+}
+
+static DBusMessage *port_get_service_name(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &node->svcname,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+static DBusMessage *port_get_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+ DBusMessageIter iter, dict;
+ char bda[18];
+ const char *pbda = bda;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dbus_message_iter_append_dict_entry(&dict, "device",
+ DBUS_TYPE_STRING, &node->device);
+
+ ba2str(&node->dst, bda);
+ dbus_message_iter_append_dict_entry(&dict, "address",
+ DBUS_TYPE_STRING, &pbda);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static GDBusMethodTable port_methods[] = {
+ { "GetAddress", "", "s", port_get_address },
+ { "GetDevice", "", "s", port_get_device },
+ { "GetAdapter", "", "s", port_get_adapter },
+ { "GetName", "", "s", port_get_name },
+ { "GetServiceName", "", "s", port_get_service_name },
+ { "GetInfo", "", "a{sv}",port_get_info },
+ { NULL, NULL, NULL, NULL },
+};
+
+static GDBusSignalTable port_signals[] = {
+ { NULL, NULL }
+};
+
+static void rfcomm_node_free(struct rfcomm_node *node)
+{
+ if (node->device)
+ g_free(node->device);
+ if (node->conn)
+ dbus_connection_unref(node->conn);
+ if (node->owner)
+ g_free(node->owner);
+ if (node->svcname)
+ g_free(node->svcname);
+ if (node->io) {
+ g_source_remove(node->io_id);
+ g_io_channel_close(node->io);
+ g_io_channel_unref(node->io);
+ }
+ rfcomm_release(node->id);
+ g_free(node);
+}
+
+static void connection_owner_exited(void *user_data)
+{
+ struct rfcomm_node *node = user_data;
+
+ debug("Connect requestor exited. Releasing %s node",
+ node->device);
+
+ g_dbus_emit_signal(node->conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
+ DBUS_TYPE_STRING, &node->device,
+ DBUS_TYPE_INVALID);
+
+ connected_nodes = g_slist_remove(connected_nodes, node);
+ rfcomm_node_free(node);
+}
+
+static gboolean rfcomm_disconnect_cb(GIOChannel *io,
+ GIOCondition cond, struct rfcomm_node *node)
+{
+ debug("RFCOMM node %s was disconnected", node->device);
+
+ g_dbus_remove_watch(node->conn, node->listener_id);
+
+ g_dbus_emit_signal(node->conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
+ DBUS_TYPE_STRING, &node->device,
+ DBUS_TYPE_INVALID);
+
+ connected_nodes = g_slist_remove(connected_nodes, node);
+ rfcomm_node_free(node);
+
+ return FALSE;
+}
+
+static void port_handler_unregister(void *data)
+{
+ struct rfcomm_node *node = data;
+
+ debug("Unregistered serial port: %s", node->device);
+
+ bound_nodes = g_slist_remove(bound_nodes, node);
+ rfcomm_node_free(node);
+}
+
+void port_add_listener(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+ int fd, const char *dev, const char *owner)
+{
+ struct rfcomm_node *node;
+
+ node = g_new0(struct rfcomm_node, 1);
+ bacpy(&node->dst, dst);
+ node->id = id;
+ node->device = g_strdup(dev);
+ node->conn = dbus_connection_ref(conn);
+ node->owner = g_strdup(owner);
+ node->io = g_io_channel_unix_new(fd);
+ node->io_id = g_io_add_watch(node->io, G_IO_ERR | G_IO_NVAL | G_IO_HUP,
+ (GIOFunc) rfcomm_disconnect_cb, node);
+
+ connected_nodes = g_slist_append(connected_nodes, node);
+
+ /* Service connection listener */
+ node->listener_id = g_dbus_add_disconnect_watch(conn, owner,
+ connection_owner_exited, node,
+ NULL);
+}
+
+int port_remove_listener(const char *owner, const char *dev)
+{
+ struct rfcomm_node *node;
+
+ node = find_node_by_name(connected_nodes, dev);
+ if (!node)
+ return -ENOENT;
+ if (strcmp(node->owner, owner) != 0)
+ return -EPERM;
+
+ g_dbus_remove_watch(node->conn, node->listener_id);
+
+ connected_nodes = g_slist_remove(connected_nodes, node);
+ rfcomm_node_free(node);
+
+ return 0;
+}
+
+void port_release_all(void)
+{
+ struct rfcomm_node *node;
+ GSList *l;
+
+ for (l = connected_nodes; l; l = l->next) {
+ node = l->data;
+
+ connected_nodes = g_slist_remove(connected_nodes, node);
+ rfcomm_node_free(node);
+ }
+}
+
+int port_register(DBusConnection *conn, int16_t id, bdaddr_t *src,
+ bdaddr_t *dst, const char *dev, char *ppath, const char *svc)
+{
+ char path[MAX_PATH_LENGTH];
+ struct rfcomm_node *node;
+
+ node = g_new0(struct rfcomm_node, 1);
+ bacpy(&node->dst, dst);
+ bacpy(&node->src, src);
+ node->id = id;
+ node->device = g_strdup(dev);
+ node->conn = dbus_connection_ref(conn);
+ node->svcname = g_strdup(svc?:"Bluetooth RFCOMM port");
+
+ snprintf(path, MAX_PATH_LENGTH, "%s/rfcomm%hd", SERIAL_MANAGER_PATH, id);
+
+
+ if (!g_dbus_register_interface(conn, path,
+ SERIAL_PORT_INTERFACE,
+ port_methods, port_signals, NULL,
+ node, port_handler_unregister)) {
+ error("D-Bus failed to register %s interface",
+ SERIAL_PORT_INTERFACE);
+ rfcomm_node_free(node);
+ return -1;
+ }
+
+ info("Registered RFCOMM:%s, path:%s", dev, path);
+
+ if (ppath)
+ strcpy(ppath, path);
+
+ bound_nodes = g_slist_append(bound_nodes, node);
+
+ return 0;
+}
+
+int port_unregister(const char *path)
+{
+ struct rfcomm_node *node;
+ char dev[16];
+ int16_t id;
+
+ if (sscanf(path, SERIAL_MANAGER_PATH"/rfcomm%hd", &id) != 1)
+ return -ENOENT;
+
+ snprintf(dev, sizeof(dev), "/dev/rfcomm%hd", id);
+ node = find_node_by_name(bound_nodes, dev);
+ if (!node)
+ return -ENOENT;
+
+ g_dbus_unregister_interface(node->conn, path, SERIAL_PORT_INTERFACE);
+
+ return 0;
+}
diff --git a/utils/serial/port.h b/utils/serial/port.h
new file mode 100644
index 00000000..5471525b
--- /dev/null
+++ b/utils/serial/port.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 port_add_listener(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+ int fd, const char *dev, const char *owner);
+
+int port_remove_listener(const char *owner, const char *dev);
+
+void port_release_all(void);
+
+int port_register(DBusConnection *conn, int16_t id, bdaddr_t *src,
+ bdaddr_t *dst, const char *dev, char *ppath, const char *svc);
+
+int port_unregister(const char *path);
diff --git a/utils/serial/serial-api.txt b/utils/serial/serial-api.txt
new file mode 100644
index 00000000..7e17b86e
--- /dev/null
+++ b/utils/serial/serial-api.txt
@@ -0,0 +1,176 @@
+Bluetooth serial service API description
+****************************************
+
+Copyright (C) 2006-2007 Marcel Holtmann <marcel@holtmann.org>
+
+
+Manager hierarchy
+=================
+
+Interface org.bluez.serial.Manager
+Object path /org/bluez/serial
+
+Methods string CreateProxy(string uuid, string address)
+
+ Creates a serial port proxy object.
+
+ Service identifier must be provided in the uuid 128
+ format. Addresses can be either TTY char devices,
+ unix socket address or a local TCP port. Abstract
+ namespace can be informed replacing the null byte
+ by 'x00'. eg: "/dev/ttyS0", "/tmp/gps-data",
+ "x00/org/bluez/echo", "localhost:2947".
+
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotAvailable
+ org.bluez.Error.Failed
+
+ void RemoveProxy(string path) [experimental]
+
+ Removes the serial port proxy object for given path.
+
+ Possible errors:org.bluez.Error.DoesNotExist
+
+ string CreatePort(string address, string pattern) [experimental]
+
+ Creates a serial port object.
+
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.Canceled
+ org.bluez.Error.InProgress
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.NotSupported
+ org.bluez.Error.Failed
+
+ void RemovePort(string path) [experimental]
+
+ Removes the serial port object for given path.
+
+ Possible errors:org.bluez.Error.DoesNotExist
+
+ array{string} ListPorts() [experimental]
+
+ Returns an array of available serial port paths.
+
+ array{string} ListProxies() [experimental]
+
+ Returns an array of available serial port proxy paths.
+
+ string ConnectService(string address, string pattern)
+
+ Connects to a specific RFCOMM based service on a
+ remote device and then creates a RFCOMM TTY
+ device for it. The RFCOMM TTY device is returned.
+
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.Canceled
+ org.bluez.Error.InProgress
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.NotSupported
+ org.bluez.Error.Failed
+
+ string ConnectServiceFromAdapter(string adapter,
+ string address, string pattern) [experimental]
+
+ Use the given adapter to connect to a specific RFCOMM
+ based service on a remote device and then creates a
+ RFCOMM TTY device for it. The RFCOMM TTY device is
+ returned.
+
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.Canceled
+ org.bluez.Error.InProgress
+ org.bluez.Error.ConnectionAttemptFailed
+ org.bluez.Error.NotSupported
+ org.bluez.Error.Failed
+
+ void CancelConnectService(string address, string pattern)
+
+ Cancel a previous ConnectService method call.
+
+ Possible errors:org.bluez.serial.InvalidArguments
+
+ void DisconnectService(string device)
+
+ Disconnect a RFCOMM TTY device that has been
+ created via the ConnectService method.
+
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.DoesNotExist
+
+Signals void PortCreated(string path) [experimental]
+
+ void PortRemoved(string path) [experimental]
+
+ void ProxyCreated(string path) [experimental]
+
+ void ProxyRemoved(string path) [experimental]
+
+ void ServiceConnected(string device)
+
+ void ServiceDisconnected(string device)
+
+
+Port hierarchy (experimental)
+=============================
+
+Interface org.bluez.serial.Port
+Object path /org/bluez/serial/rfcomm*
+
+Methods string GetAdapter() [experimental]
+
+ Returns the adapter address.
+
+ string GetAddress() [experimental]
+
+ Returns the Bluetooth address of the ending point.
+
+ string GetDevice() [experimental]
+
+ Returns the TTY device node name
+
+ dict GetInfo() [experimental]
+
+ Returns the port properties.
+
+ string GetName()
+
+ Returns the name of the remote device.
+
+ string GetServiceName()
+
+ Returns the name of the remote service.
+ e.g.: "Dial-up networking Gateway"
+
+Proxy hierarchy (experimental)
+=============================
+Interface org.bluez.serial.Proxy
+Object path /org/bluez/serial/rfcomm*
+
+Methods: void Enable() [experimental]
+
+ Register the serial proxy service record and start
+ listenning on the specified adapter/channel.
+
+ Possible errors:org.bluez.Error.Failed
+
+ void Disable() [experimental]
+
+ Unregister the service record and stop listenning.
+
+ Possible errors:org.bluez.Error.Failed
+
+ dict GetInfo() [experimental]
+ Returns the proxy properties
+
+ void SetSerialParameters(string rate, byte databits,
+ byte stopbits, string parity) [experimental]
+
+ Change the TTY settings. Available rates: "50", "300",
+ "600", "1200", "1800", "2400", "4800", "9600", "19200",
+ "38400", "57600" and "115200". Available data bits: 5,
+ 6, 7 and 8. Available stop bits: 1 and 2. Available
+ parity: "even", "odd", "mark", "space" and "none".
+
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.Failed
diff --git a/utils/serial/storage.c b/utils/serial/storage.c
new file mode 100644
index 00000000..98cd5b84
--- /dev/null
+++ b/utils/serial/storage.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "textfile.h"
+
+#include "storage.h"
+
+int port_delete(bdaddr_t *src, bdaddr_t *dst, int16_t id)
+{
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ char key[32];
+
+ ba2str(src, src_addr);
+ ba2str(dst, dst_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "serial");
+ snprintf(key, sizeof(key), "%s#%hd", dst_addr, id);
+
+ return textfile_del(filename, key);
+}
+
+int port_store(bdaddr_t *src, bdaddr_t *dst, int16_t id,
+ uint8_t ch, const char *svcname)
+{
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ char key[32];
+ char *value;
+ int size, err;
+
+ if (!svcname)
+ svcname = "Bluetooth RFCOMM port";
+
+ ba2str(src, src_addr);
+ ba2str(dst, dst_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "serial");
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ size = strlen(svcname) + 5;
+ value = g_malloc0(size);
+
+ snprintf(key, 32, "%s#%hd", dst_addr, id);
+ snprintf(value, size, "%d:%s", ch, svcname);
+
+ err = textfile_put(filename, key, value);
+ g_free(value);
+
+ return err;
+}
+
+int proxy_delete(bdaddr_t *src, const char *tty)
+{
+ char filename[PATH_MAX + 1], src_addr[18];
+
+ ba2str(src, src_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "proxy");
+
+ return textfile_del(filename, tty);
+}
+
+int proxy_store(bdaddr_t *src, const char *uuid, const char *tty,
+ const char *name, uint8_t ch, int opts, struct termios *ti)
+{
+ char filename[PATH_MAX + 1], key[32], src_addr[18], *value;
+ int i, pos, size, err;
+ uint8_t *pti;
+
+ ba2str(src, src_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "proxy");
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (!name)
+ name = "Port Proxy Entity";
+
+ size = MAX_LEN_UUID_STR + 16 + strlen(name) + sizeof(struct termios) * 2;
+ value = g_malloc0(size);
+
+ snprintf(key, 32, "%s", tty);
+
+ /* tty uuid 00 0x0000 name:termios */
+ pos = snprintf(value, size, "%s %d 0x%04X %s:", uuid, ch, opts, name);
+
+ if (!ti)
+ goto done;
+
+ for (i = 0, pti = (uint8_t *) ti; i < sizeof(struct termios); i++, pti++)
+ sprintf(value + pos + (i * 2), "%2.2X", *pti);
+
+done:
+ err = textfile_put(filename, key, value);
+ g_free(value);
+
+ return err;
+}
+
+int read_device_name(bdaddr_t *src, bdaddr_t *dst, char **name)
+{
+ char filename[PATH_MAX + 1], *str;
+ char src_addr[18], dst_addr[18];
+ int len;
+
+ ba2str(src, src_addr);
+ ba2str(dst, dst_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "names");
+
+ str = textfile_get(filename, dst_addr);
+ if (!str)
+ return -ENOENT;
+
+ len = strlen(str);
+
+ /* Max remote device name */
+ if (len < 248) {
+ *name = str;
+ return 0;
+ }
+
+ *name = g_try_malloc0(248);
+ if (!*name)
+ return -ENOMEM;
+
+ snprintf(*name, 248, "%s", str);
+
+ free(str);
+
+ return 0;
+}
diff --git a/utils/serial/storage.h b/utils/serial/storage.h
new file mode 100644
index 00000000..32b04a03
--- /dev/null
+++ b/utils/serial/storage.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 port_delete(bdaddr_t *src, bdaddr_t *dst, int16_t id);
+int port_store(bdaddr_t *src, bdaddr_t *dst, int16_t id,
+ uint8_t ch, const char *svcname);
+int proxy_delete(bdaddr_t *src, const char *tty);
+int proxy_store(bdaddr_t *src, const char *uuid, const char *tty,
+ const char *name, uint8_t ch, int opts, struct termios *ti);
+int read_device_name(bdaddr_t *src, bdaddr_t *dst, char **name);
diff --git a/utils/serial/test-serial b/utils/serial/test-serial
new file mode 100755
index 00000000..aec728d4
--- /dev/null
+++ b/utils/serial/test-serial
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+import sys
+import time
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Manager')
+
+conn = manager.ActivateService('serial')
+
+serial = dbus.Interface(bus.get_object(conn, '/org/bluez/serial'),
+ 'org.bluez.serial.Manager')
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <address> [service]" % (sys.argv[0])
+ sys.exit(1)
+
+address = sys.argv[1]
+
+if (len(sys.argv) < 3):
+ service = "spp"
+else:
+ service = sys.argv[2]
+
+device = serial.ConnectService(address, service)
+
+print "Connected %s to %s" % (device, address)
+
+print "Press CTRL-C to disconnect"
+
+try:
+ time.sleep(1000)
+ print "Terminating connection"
+except:
+ pass
+
+serial.DisconnectService(device)
diff --git a/utils/test/Makefile.am b/utils/test/Makefile.am
new file mode 100644
index 00000000..16b80e7d
--- /dev/null
+++ b/utils/test/Makefile.am
@@ -0,0 +1,44 @@
+
+if TEST
+sbin_PROGRAMS = hciemu
+
+bin_PROGRAMS = l2test rctest
+
+noinst_PROGRAMS = sdptest scotest attest hstest bdaddr lmptest \
+ passkey-agent auth-agent
+
+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@
+
+bdaddr_SOURCES = bdaddr.c
+
+bdaddr_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
+
+lmptest_LDADD = @BLUEZ_LIBS@
+
+passkey_agent_LDADD = @DBUS_LIBS@
+
+auth_agent_LDADD = @DBUS_LIBS@
+
+noinst_MANS = bdaddr.8
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
+endif
+
+INCLUDES = -I$(top_srcdir)/common
+
+EXTRA_DIST = apitest hsplay hsmicro bdaddr.8 dbusdef.py
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/test/Makefile.in b/utils/test/Makefile.in
new file mode 100644
index 00000000..21f12b9e
--- /dev/null
+++ b/utils/test/Makefile.in
@@ -0,0 +1,616 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@TEST_TRUE@sbin_PROGRAMS = hciemu$(EXEEXT)
+@TEST_TRUE@bin_PROGRAMS = l2test$(EXEEXT) rctest$(EXEEXT)
+@TEST_TRUE@noinst_PROGRAMS = sdptest$(EXEEXT) scotest$(EXEEXT) \
+@TEST_TRUE@ attest$(EXEEXT) hstest$(EXEEXT) bdaddr$(EXEEXT) \
+@TEST_TRUE@ lmptest$(EXEEXT) passkey-agent$(EXEEXT) \
+@TEST_TRUE@ auth-agent$(EXEEXT)
+subdir = test
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) $(sbin_PROGRAMS)
+attest_SOURCES = attest.c
+attest_OBJECTS = attest.$(OBJEXT)
+attest_DEPENDENCIES =
+auth_agent_SOURCES = auth-agent.c
+auth_agent_OBJECTS = auth-agent.$(OBJEXT)
+auth_agent_DEPENDENCIES =
+am__bdaddr_SOURCES_DIST = bdaddr.c
+@TEST_TRUE@am_bdaddr_OBJECTS = bdaddr.$(OBJEXT)
+bdaddr_OBJECTS = $(am_bdaddr_OBJECTS)
+@TEST_TRUE@bdaddr_DEPENDENCIES = $(top_builddir)/common/libhelper.a
+hciemu_SOURCES = hciemu.c
+hciemu_OBJECTS = hciemu.$(OBJEXT)
+@TEST_TRUE@hciemu_DEPENDENCIES = $(top_builddir)/common/libhelper.a
+hstest_SOURCES = hstest.c
+hstest_OBJECTS = hstest.$(OBJEXT)
+hstest_DEPENDENCIES =
+l2test_SOURCES = l2test.c
+l2test_OBJECTS = l2test.$(OBJEXT)
+l2test_DEPENDENCIES =
+lmptest_SOURCES = lmptest.c
+lmptest_OBJECTS = lmptest.$(OBJEXT)
+lmptest_DEPENDENCIES =
+passkey_agent_SOURCES = passkey-agent.c
+passkey_agent_OBJECTS = passkey-agent.$(OBJEXT)
+passkey_agent_DEPENDENCIES =
+rctest_SOURCES = rctest.c
+rctest_OBJECTS = rctest.$(OBJEXT)
+rctest_DEPENDENCIES =
+scotest_SOURCES = scotest.c
+scotest_OBJECTS = scotest.$(OBJEXT)
+scotest_DEPENDENCIES =
+sdptest_SOURCES = sdptest.c
+sdptest_OBJECTS = sdptest.$(OBJEXT)
+sdptest_DEPENDENCIES =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = attest.c auth-agent.c $(bdaddr_SOURCES) hciemu.c hstest.c \
+ l2test.c lmptest.c passkey-agent.c rctest.c scotest.c \
+ sdptest.c
+DIST_SOURCES = attest.c auth-agent.c $(am__bdaddr_SOURCES_DIST) \
+ hciemu.c hstest.c l2test.c lmptest.c passkey-agent.c rctest.c \
+ scotest.c sdptest.c
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@TEST_TRUE@hciemu_LDADD = $(top_builddir)/common/libhelper.a \
+@TEST_TRUE@ @GLIB_LIBS@ @BLUEZ_LIBS@
+
+@TEST_TRUE@l2test_LDADD = @BLUEZ_LIBS@
+@TEST_TRUE@rctest_LDADD = @BLUEZ_LIBS@
+@TEST_TRUE@sdptest_LDADD = @BLUEZ_LIBS@
+@TEST_TRUE@scotest_LDADD = @BLUEZ_LIBS@
+@TEST_TRUE@attest_LDADD = @BLUEZ_LIBS@
+@TEST_TRUE@hstest_LDADD = @BLUEZ_LIBS@
+@TEST_TRUE@bdaddr_SOURCES = bdaddr.c
+@TEST_TRUE@bdaddr_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
+@TEST_TRUE@lmptest_LDADD = @BLUEZ_LIBS@
+@TEST_TRUE@passkey_agent_LDADD = @DBUS_LIBS@
+@TEST_TRUE@auth_agent_LDADD = @DBUS_LIBS@
+@TEST_TRUE@noinst_MANS = bdaddr.8
+@TEST_TRUE@AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
+EXTRA_DIST = apitest hsplay hsmicro bdaddr.8 dbusdef.py
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu test/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sbindir)/$$f"; \
+ done
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+attest$(EXEEXT): $(attest_OBJECTS) $(attest_DEPENDENCIES)
+ @rm -f attest$(EXEEXT)
+ $(LINK) $(attest_OBJECTS) $(attest_LDADD) $(LIBS)
+auth-agent$(EXEEXT): $(auth_agent_OBJECTS) $(auth_agent_DEPENDENCIES)
+ @rm -f auth-agent$(EXEEXT)
+ $(LINK) $(auth_agent_OBJECTS) $(auth_agent_LDADD) $(LIBS)
+bdaddr$(EXEEXT): $(bdaddr_OBJECTS) $(bdaddr_DEPENDENCIES)
+ @rm -f bdaddr$(EXEEXT)
+ $(LINK) $(bdaddr_OBJECTS) $(bdaddr_LDADD) $(LIBS)
+hciemu$(EXEEXT): $(hciemu_OBJECTS) $(hciemu_DEPENDENCIES)
+ @rm -f hciemu$(EXEEXT)
+ $(LINK) $(hciemu_OBJECTS) $(hciemu_LDADD) $(LIBS)
+hstest$(EXEEXT): $(hstest_OBJECTS) $(hstest_DEPENDENCIES)
+ @rm -f hstest$(EXEEXT)
+ $(LINK) $(hstest_OBJECTS) $(hstest_LDADD) $(LIBS)
+l2test$(EXEEXT): $(l2test_OBJECTS) $(l2test_DEPENDENCIES)
+ @rm -f l2test$(EXEEXT)
+ $(LINK) $(l2test_OBJECTS) $(l2test_LDADD) $(LIBS)
+lmptest$(EXEEXT): $(lmptest_OBJECTS) $(lmptest_DEPENDENCIES)
+ @rm -f lmptest$(EXEEXT)
+ $(LINK) $(lmptest_OBJECTS) $(lmptest_LDADD) $(LIBS)
+passkey-agent$(EXEEXT): $(passkey_agent_OBJECTS) $(passkey_agent_DEPENDENCIES)
+ @rm -f passkey-agent$(EXEEXT)
+ $(LINK) $(passkey_agent_OBJECTS) $(passkey_agent_LDADD) $(LIBS)
+rctest$(EXEEXT): $(rctest_OBJECTS) $(rctest_DEPENDENCIES)
+ @rm -f rctest$(EXEEXT)
+ $(LINK) $(rctest_OBJECTS) $(rctest_LDADD) $(LIBS)
+scotest$(EXEEXT): $(scotest_OBJECTS) $(scotest_DEPENDENCIES)
+ @rm -f scotest$(EXEEXT)
+ $(LINK) $(scotest_OBJECTS) $(scotest_LDADD) $(LIBS)
+sdptest$(EXEEXT): $(sdptest_OBJECTS) $(sdptest_DEPENDENCIES)
+ @rm -f sdptest$(EXEEXT)
+ $(LINK) $(sdptest_OBJECTS) $(sdptest_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth-agent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bdaddr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hciemu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hstest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/l2test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmptest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/passkey-agent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rctest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scotest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdptest.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool \
+ clean-noinstPROGRAMS clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-sbinPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool clean-noinstPROGRAMS \
+ clean-sbinPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-sbinPROGRAMS install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-sbinPROGRAMS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/test/apitest b/utils/test/apitest
new file mode 100755
index 00000000..b1c3f103
--- /dev/null
+++ b/utils/test/apitest
@@ -0,0 +1,448 @@
+#!/usr/bin/env python
+
+import dbus
+import dbus.decorators
+import dbus.glib
+import gobject
+import sys
+import getopt
+from signal import *
+
+mgr_cmds = [ "InterfaceVersion", "ListAdapters", "DefaultAdapter" ]
+mgr_signals = [ "AdapterAdded", "AdapterRemoved" ]
+
+dev_cmds = [ "GetAddress",
+ "GetVersion",
+ "GetRevision",
+ "GetManufacturer",
+ "GetCompany",
+ "GetMode",
+ "SetMode",
+ "GetDiscoverableTimeout",
+ "SetDiscoverableTimeout",
+ "IsConnectable",
+ "IsDiscoverable",
+ "IsConnected",
+ "ListConnections",
+ "GetMajorClass",
+ "ListAvailableMinorClasses",
+ "GetMinorClass",
+ "SetMinorClass",
+ "GetServiceClasses",
+ "GetName",
+ "SetName",
+ "GetRemoteVersion",
+ "GetRemoteRevision",
+ "GetRemoteManufacturer",
+ "GetRemoteCompany",
+ "GetRemoteMajorClass",
+ "GetRemoteMinorClass",
+ "GetRemoteServiceClasses",
+ "GetRemoteClass",
+ "GetRemoteName",
+ "GetRemoteAlias",
+ "SetRemoteAlias",
+ "ClearRemoteAlias",
+ "LastSeen",
+ "LastUsed",
+ "DisconnectRemoteDevice",
+ "CreateBonding",
+ "CancelBondingProcess",
+ "RemoveBonding",
+ "HasBonding",
+ "ListBondings",
+ "GetPinCodeLength",
+ "GetEncryptionKeySize",
+ "DiscoverDevices",
+ "DiscoverDevicesWithoutNameResolving",
+ "CancelDiscovery",
+ "ListRemoteDevices",
+ "ListRecentRemoteDevices" ]
+dev_signals = [ "ModeChanged",
+ "NameChanged",
+ "MinorClassChanged",
+ "DiscoveryStarted",
+ "DiscoveryCompleted",
+ "RemoteDeviceFound",
+ "RemoteNameUpdated",
+ "RemoteNameFailed",
+ "RemoteAliasChanged"
+ "RemoteAliasCleared",
+ "RemoteDeviceConnected",
+ "RemoteDeviceDisconnectRequested",
+ "RemoteDeviceDisconnected",
+ "BondingCreated",
+ "BondingRemoved" ]
+
+dev_signals_filter = [ "/org/bluez/hci0", "/org/bluez/hci1",
+ "/org/bluez/hci2", "/org/bluez/hci3",
+ "/org/bluez/hci4", "/org/bluez/hci5",
+ "/org/bluez/hci6", "/org/bluez/hci7" ]
+
+class Tester:
+ exit_events = []
+ dev_path = None
+ need_dev = False
+ listen = False
+ at_interrupt = None
+
+ def __init__(self, argv):
+ self.name = argv[0]
+
+ self.parse_args(argv[1:])
+
+ try:
+ self.dbus_setup()
+ except dbus.DBusException, e:
+ print 'Failed to do D-Bus setup: %s' % e
+ sys.exit(1)
+
+ def parse_args(self, argv):
+ try:
+ opts, args = getopt.getopt(argv, "hli:")
+ except getopt.GetoptError:
+ self.usage()
+ sys.exit(1)
+
+ for o, a in opts:
+ if o == "-h":
+ self.usage()
+ sys.exit()
+ elif o == "-l":
+ self.listen = True
+ elif o == "-i":
+ if a[0] == '/':
+ self.dev_path = a
+ else:
+ self.dev_path = '/org/bluez/%s' % a
+
+ if not (args or self.listen):
+ self.usage()
+ sys.exit(1)
+
+ if args:
+ self.cmd = args[0]
+ self.cmd_args = args[1:]
+
+ def dbus_dev_setup(self):
+ if not self.dev_path:
+ try:
+ self.dbus_mgr_setup()
+ self.dev_path = self.manager.DefaultAdapter()
+ except dbus.DBusException, e:
+ print 'Failed to get default device: %s' % e
+ sys.exit(1)
+ try:
+ obj = self.bus.get_object('org.bluez', self.dev_path)
+ self.device = dbus.Interface(obj, 'org.bluez.Adapter')
+ except dbus.DBusException, e:
+ print 'Failed to setup device path: %s' % e
+ sys.exit(1)
+
+ def dbus_dev_sig_setup(self):
+ try:
+ for signal in dev_signals:
+ for path in dev_signals_filter:
+ self.bus.add_signal_receiver(self.dev_signal_handler,
+ signal, 'org.bluez.Adapter',
+ 'org.bluez', path,
+ message_keyword='dbus_message')
+ except dbus.DBusException, e:
+ print 'Failed to setup signal handler for device path: %s' % e
+ sys.exit(1)
+
+ def dbus_mgr_sig_setup(self):
+ try:
+ for signal in mgr_signals:
+ self.bus.add_signal_receiver(self.mgr_signal_handler,
+ signal,'org.bluez.Manager',
+ 'org.bluez', '/org/bluez')
+ except dbus.DBusException, e:
+ print 'Failed to setup signal handler for manager path: %s' % e
+ sys.exit(1)
+
+ def dbus_mgr_setup(self):
+ self.manager_obj = self.bus.get_object('org.bluez', '/org/bluez')
+ self.manager = dbus.Interface(self.manager_obj, 'org.bluez.Manager')
+
+ def dbus_setup(self):
+ self.bus = dbus.SystemBus()
+
+ def usage(self):
+ print 'Usage: %s [-i <dev>] [-l] [-h] <cmd> [arg1..]' % self.name
+ print ' -i <dev> Specify device (e.g. "hci0" or "/org/bluez/hci0")'
+ print ' -l Listen for events (no command required)'
+ print ' -h Show this help'
+ print 'Manager commands:'
+ for cmd in mgr_cmds:
+ print '\t%s' % cmd
+ print 'Adapter commands:'
+ for cmd in dev_cmds:
+ print '\t%s' % cmd
+
+ #@dbus.decorators.explicitly_pass_message
+ def dev_signal_handler(*args, **keywords):
+ dbus_message = keywords["dbus_message"]
+ print '%s - %s: ' % (dbus_message.get_member(), dbus_message.get_path()),
+ for arg in args[1:]:
+ print '%s ' % arg,
+ print
+
+ #@dbus.decorators.explicitly_pass_message
+ def mgr_signal_handler(*args, **keywords):
+ dbus_message = keywords["dbus_message"]
+ print '%s: ' % dbus_message.get_member()
+ for arg in args[1:]:
+ print '%s ' % arg,
+ print
+
+ def signal_cb(self, sig, frame):
+ print 'Caught signal, exiting'
+ if self.at_interrupt:
+ self.at_interrupt()
+ self.main_loop.quit()
+
+ def call_mgr_dbus_func(self):
+ if self.cmd == 'InterfaceVersion':
+ try:
+ print self.manager.InterfaceVersion()
+ except dbus.DBusException, e:
+ print 'Sending %s failed: %s' % (self.cmd, e)
+ if self.cmd == 'ListAdapters':
+ try:
+ devices = self.manager.ListAdapters()
+ except dbus.DBusException, e:
+ print 'Sending %s failed: %s' % (self.cmd, e)
+ sys.exit(1)
+ for device in devices:
+ print device
+ elif self.cmd == 'DefaultAdapter':
+ try:
+ print self.manager.DefaultAdapter()
+ except dbus.DBusException, e:
+ print 'Sending %s failed: %s' % (self.cmd, e)
+ sys.exit(1)
+
+ def call_dev_dbus_func(self):
+ try:
+ if self.cmd == 'GetAddress':
+ print self.device.GetAddress()
+ elif self.cmd == 'GetManufacturer':
+ print self.device.GetManufacturer()
+ elif self.cmd == 'GetVersion':
+ print self.device.GetVersion()
+ elif self.cmd == 'GetRevision':
+ print self.device.GetRevision()
+ elif self.cmd == 'GetCompany':
+ print self.device.GetCompany()
+ elif self.cmd == 'GetMode':
+ print self.device.GetMode()
+ elif self.cmd == 'SetMode':
+ if len(self.cmd_args) == 1:
+ self.device.SetMode(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> SetMode scan_mode' % self.name
+ elif self.cmd == 'GetDiscoverableTimeout':
+ print '%u' % (self.device.GetDiscoverableTimeout())
+ elif self.cmd == 'SetDiscoverableTimeout':
+ if len(self.cmd_args) == 1:
+ self.device.SetDiscoverableTimeout(dbus.UInt32(self.cmd_args[0]))
+ else:
+ print 'Usage: %s -i <dev> SetDiscoverableTimeout timeout' % self.name
+ elif self.cmd == 'IsConnectable':
+ print self.device.IsConnectable()
+ elif self.cmd == 'IsDiscoverable':
+ print self.device.IsDiscoverable()
+ elif self.cmd == 'IsConnected':
+ if len(self.cmd_args) == 1:
+ print self.device.IsConnected(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> IsConnected address' % self.name
+ elif self.cmd == 'ListConnections':
+ print self.device.ListConnections()
+ elif self.cmd == 'GetMajorClass':
+ print self.device.GetMajorClass()
+ elif self.cmd == 'ListAvailableMinorClasses':
+ print self.device.ListAvailableMinorClasses()
+ elif self.cmd == 'GetMinorClass':
+ print self.device.GetMinorClass()
+ elif self.cmd == 'SetMinorClass':
+ if len(self.cmd_args) == 1:
+ self.device.SetMinorClass(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> SetMinorClass minor' % self.name
+ elif self.cmd == 'GetServiceClasses':
+ classes = self.device.GetServiceClasses()
+ for clas in classes:
+ print clas,
+ elif self.cmd == 'GetName':
+ print self.device.GetName()
+ elif self.cmd == 'SetName':
+ if len(self.cmd_args) == 1:
+ self.device.SetName(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> SetName newname' % self.name
+ elif self.cmd == 'GetRemoteName':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteName(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteName address' % self.name
+ elif self.cmd == 'GetRemoteVersion':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteVersion(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteVersion address' % self.name
+ elif self.cmd == 'GetRemoteRevision':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteRevision(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteRevision address' % self.name
+ elif self.cmd == 'GetRemoteManufacturer':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteManufacturer(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteManufacturer address' % self.name
+ elif self.cmd == 'GetRemoteCompany':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteCompany(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteCompany address' % self.name
+ elif self.cmd == 'GetRemoteAlias':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteAlias(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteAlias address' % self.name
+ elif self.cmd == 'GetRemoteMajorClass':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteMajorClass(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteMajorClass address' % self.name
+ elif self.cmd == 'GetRemoteMinorClass':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteMinorClass(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteMinorClass address' % self.name
+ elif self.cmd == 'GetRemoteServiceClasses':
+ if len(self.cmd_args) == 1:
+ print self.device.GetRemoteServiceClasses(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetRemoteServiceClasses address' % self.name
+ elif self.cmd == 'SetRemoteAlias':
+ if len(self.cmd_args) == 2:
+ self.device.SetRemoteAlias(self.cmd_args[0], self.cmd_args[1])
+ else:
+ print 'Usage: %s -i <dev> SetRemoteAlias address alias' % self.name
+ elif self.cmd == 'ClearRemoteAlias':
+ if len(self.cmd_args) == 1:
+ print self.device.ClearRemoteAlias(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> ClearRemoteAlias address' % self.name
+ elif self.cmd == 'LastSeen':
+ if len(self.cmd_args) == 1:
+ print self.device.LastSeen(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> LastSeen address' % self.name
+ elif self.cmd == 'LastUsed':
+ if len(self.cmd_args) == 1:
+ print self.device.LastUsed(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> LastUsed address' % self.name
+ elif self.cmd == 'DisconnectRemoteDevice':
+ if len(self.cmd_args) == 1:
+ print self.device.LastUsed(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> DisconnectRemoteDevice address' % self.name
+ elif self.cmd == 'CreateBonding':
+ if len(self.cmd_args) == 1:
+ print self.device.CreateBonding(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> CreateBonding address' % self.name
+ elif self.cmd == 'RemoveBonding':
+ if len(self.cmd_args) == 1:
+ print self.device.RemoveBonding(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> RemoveBonding address' % self.name
+ elif self.cmd == 'CancelBondingProcess':
+ if len(self.cmd_args) == 1:
+ print self.device.CancelBondingProcess(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> CancelBondingProcess address' % self.name
+ elif self.cmd == 'HasBonding':
+ if len(self.cmd_args) == 1:
+ print self.device.HasBonding(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> HasBonding address' % self.name
+ elif self.cmd == 'ListBondings':
+ bondings = self.device.ListBondings()
+ for bond in bondings:
+ print bond,
+ elif self.cmd == 'GetPinCodeLength':
+ if len(self.cmd_args) == 1:
+ print self.device.GetPinCodeLength(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetPinCodeLength address' % self.name
+ elif self.cmd == 'GetEncryptionKeySize':
+ if len(self.cmd_args) == 1:
+ print self.device.GetEncryptionKeySize(self.cmd_args[0])
+ else:
+ print 'Usage: %s -i <dev> GetEncryptionKeySize address' % self.name
+ elif self.cmd == 'DiscoverDevices':
+ print self.device.DiscoverDevices()
+ elif self.cmd == 'DiscoverDevicesWithoutNameResolving':
+ print self.device.DiscoverDevicesWithoutNameResolving()
+ elif self.cmd == 'ListRemoteDevices':
+ devices = self.device.ListRemoteDevices()
+ for device in devices:
+ print device,
+ elif self.cmd == 'ListRecentRemoteDevices':
+ if len(self.cmd_args) == 1:
+ devices = self.device.ListRecentRemoteDevices(self.cmd_args[0])
+ for device in devices:
+ print device,
+ else:
+ print 'Usage: %s -i <dev> ListRecentRemoteDevices date' % self.name
+ else:
+ # FIXME: remove at future version
+ print 'Script Error: Method %s not found. Maybe a mispelled word.' % (self.cmd_args)
+ except dbus.DBusException, e:
+ print '%s failed: %s' % (self.cmd, e)
+ sys.exit(1)
+
+ def run(self):
+ # Manager methods
+ if self.listen:
+ self.dbus_mgr_sig_setup()
+ self.dbus_dev_sig_setup()
+ print 'Listening for events...'
+
+ if self.cmd in mgr_cmds:
+ try:
+ self.dbus_mgr_setup()
+ except dbus.DBusException, e:
+ print 'Failed to setup manager interface: %s' % e
+ sys.exit(1)
+ self.call_mgr_dbus_func()
+ elif self.cmd in dev_cmds:
+ try:
+ self.dbus_dev_setup()
+ except dbus.DBusException, e:
+ print 'Failed to setup device interface: %s' % e
+ sys.exit(1)
+ self.call_dev_dbus_func()
+ elif not self.listen:
+ print 'Unknown command: %s' % self.cmd
+ self.usage()
+ sys.exit(1)
+
+ if self.listen:
+ signal(SIGINT, self.signal_cb)
+ signal(SIGTERM, self.signal_cb)
+ self.main_loop = gobject.MainLoop()
+ self.main_loop.run()
+
+if __name__ == '__main__':
+ gobject.threads_init()
+ dbus.glib.init_threads()
+
+ tester = Tester(sys.argv)
+ tester.run()
diff --git a/utils/test/attest.c b/utils/test/attest.c
new file mode 100644
index 00000000..531c2157
--- /dev/null
+++ b/utils/test/attest.c
@@ -0,0 +1,183 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+static int at_command(int fd, char *cmd, int to)
+{
+ fd_set rfds;
+ struct timeval timeout;
+ char buf[1024];
+ int sel, len, i, n;
+
+ len = write(fd, cmd, strlen(cmd));
+
+ for (i = 0; i < 100; i++) {
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = to;
+
+ if ((sel = select(fd + 1, &rfds, NULL, NULL, &timeout)) > 0) {
+
+ if (FD_ISSET(fd, &rfds)) {
+ memset(buf, 0, sizeof(buf));
+ len = read(fd, buf, sizeof(buf));
+ for (n = 0; n < len; n++)
+ printf("%c", buf[n]);
+ if (strstr(buf, "\r\nOK") != NULL)
+ break;
+ if (strstr(buf, "\r\nERROR") != NULL)
+ break;
+ if (strstr(buf, "\r\nCONNECT") != NULL)
+ break;
+ }
+
+ }
+
+ }
+
+ return 0;
+}
+
+static int open_device(char *device)
+{
+ struct termios ti;
+ int fd;
+
+ fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open serial port: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ /* Switch tty to RAW mode */
+ cfmakeraw(&ti);
+ tcsetattr(fd, TCSANOW, &ti);
+
+ return fd;
+}
+
+static int open_socket(bdaddr_t *bdaddr, uint8_t channel)
+{
+ struct sockaddr_rc addr;
+ int sk;
+
+ sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ fprintf(stderr, "Can't create socket: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, BDADDR_ANY);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ fprintf(stderr, "Can't bind socket: %s (%d)\n",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, bdaddr);
+ addr.rc_channel = channel;
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ fprintf(stderr, "Can't connect: %s (%d)\n",
+ strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+
+ return sk;
+}
+
+static void usage(void)
+{
+ printf("Usage:\n\tattest <device> | <bdaddr> [channel]\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+
+ bdaddr_t bdaddr;
+ uint8_t channel;
+
+ switch (argc) {
+ case 2:
+ str2ba(argv[1], &bdaddr);
+ channel = 1;
+ break;
+ case 3:
+ str2ba(argv[1], &bdaddr);
+ channel = atoi(argv[2]);
+ break;
+ default:
+ usage();
+ exit(-1);
+ }
+
+ if (bacmp(BDADDR_ANY, &bdaddr)) {
+ printf("Connecting to %s on channel %d\n", argv[1], channel);
+ fd = open_socket(&bdaddr, channel);
+ } else {
+ printf("Opening device %s\n", argv[1]);
+ fd = open_device(argv[1]);
+ }
+
+ if (fd < 0)
+ exit(-2);
+
+ at_command(fd, "ATZ\r\n", 10000);
+ at_command(fd, "AT+CPBS=\"ME\"\r\n", 10000);
+ at_command(fd, "AT+CPBR=1,100\r\n", 100000);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/utils/test/auth-agent.c b/utils/test/auth-agent.c
new file mode 100644
index 00000000..2686c3ee
--- /dev/null
+++ b/utils/test/auth-agent.c
@@ -0,0 +1,351 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+#define INTERFACE "org.bluez.Security"
+
+static volatile sig_atomic_t __io_canceled = 0;
+static volatile sig_atomic_t __io_terminated = 0;
+
+static void sig_term(int sig)
+{
+ __io_canceled = 1;
+}
+
+static DBusHandlerResult agent_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *name, *old, *new;
+
+ if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!strcmp(name, "org.bluez") && *new == '\0') {
+ fprintf(stderr, "Authorization service has been terminated\n");
+ __io_terminated = 1;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult authorize_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *adapter, *address, *service, *string;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &service, DBUS_TYPE_STRING, &string,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for passkey Confirm method");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ printf("Authorization request for device %s\n", address);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ fprintf(stderr, "Can't create reply message\n");
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult cancel_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *adapter, *address, *service, *string;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &service, DBUS_TYPE_STRING, &string,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for passkey Confirm method");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ printf("Request canceled for device %s\n", address);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ fprintf(stderr, "Can't create reply message\n");
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult release_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for Release method");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!__io_canceled)
+ fprintf(stderr, "Authorization agent has been released\n");
+
+ __io_terminated = 1;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ fprintf(stderr, "Can't create reply message\n");
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult auth_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ if (dbus_message_is_method_call(msg, "org.bluez.AuthorizationAgent", "Authorize"))
+ return authorize_message(conn, msg, data);
+
+ if (dbus_message_is_method_call(msg, "org.bluez.AuthorizationAgent", "Cancel"))
+ return cancel_message(conn, msg, data);
+
+ if (dbus_message_is_method_call(msg, "org.bluez.AuthorizationAgent", "Release"))
+ return release_message(conn, msg, data);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static const DBusObjectPathVTable auth_table = {
+ .message_function = auth_message,
+};
+
+static int register_auth(DBusConnection *conn, const char *auth_path)
+{
+ DBusMessage *msg, *reply;
+ DBusError err;
+
+ if (!dbus_connection_register_object_path(conn, auth_path,
+ &auth_table, NULL)) {
+ fprintf(stderr, "Can't register object path for agent\n");
+ return -1;
+ }
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ INTERFACE, "RegisterDefaultAuthorizationAgent");
+ if (!msg) {
+ fprintf(stderr, "Can't allocate new method call\n");
+ return -1;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &auth_path,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ fprintf(stderr, "Can't register authorization agent\n");
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "%s\n", err.message);
+ dbus_error_free(&err);
+ }
+ return -1;
+ }
+
+ dbus_message_unref(reply);
+
+ dbus_connection_flush(conn);
+
+ return 0;
+}
+
+static int unregister_auth(DBusConnection *conn, const char *auth_path)
+{
+ DBusMessage *msg, *reply;
+ DBusError err;
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ INTERFACE, "UnregisterDefaultAuthorizationAgent");
+ if (!msg) {
+ fprintf(stderr, "Can't allocate new method call\n");
+ dbus_connection_unref(conn);
+ exit(1);
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &auth_path,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ fprintf(stderr, "Can't unregister authorization agent\n");
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "%s\n", err.message);
+ dbus_error_free(&err);
+ }
+ return -1;
+ }
+
+ dbus_message_unref(reply);
+
+ dbus_connection_flush(conn);
+
+ dbus_connection_unregister_object_path(conn, auth_path);
+
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Bluetooth authorization agent ver %s\n\n", VERSION);
+
+ printf("Usage:\n"
+ "\tauth-agent [--path auth-path]\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "path", 1, 0, 'p' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ DBusConnection *conn;
+ char match_string[128], default_path[128], *auth_path = NULL;
+ int opt;
+
+ snprintf(default_path, sizeof(default_path),
+ "/org/bluez/auth_agent_%d", getpid());
+
+ while ((opt = getopt_long(argc, argv, "+p:h", main_options, NULL)) != EOF) {
+ switch(opt) {
+ case 'p':
+ if (optarg[0] != '/') {
+ fprintf(stderr, "Invalid path\n");
+ exit(1);
+ }
+ auth_path = strdup(optarg);
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (!auth_path)
+ auth_path = strdup(default_path);
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ fprintf(stderr, "Can't get on system bus");
+ exit(1);
+ }
+
+ if (register_auth(conn, auth_path) < 0) {
+ dbus_connection_unref(conn);
+ exit(1);
+ }
+
+ if (!dbus_connection_add_filter(conn, agent_filter, NULL, NULL))
+ fprintf(stderr, "Can't add signal filter");
+
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, "org.bluez");
+
+ dbus_bus_add_match(conn, match_string, NULL);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ while (!__io_canceled && !__io_terminated) {
+ if (dbus_connection_read_write_dispatch(conn, 500) != TRUE)
+ break;
+ }
+
+ if (!__io_terminated)
+ unregister_auth(conn, auth_path);
+
+ dbus_connection_unref(conn);
+
+ return 0;
+}
diff --git a/utils/test/bdaddr.8 b/utils/test/bdaddr.8
new file mode 100644
index 00000000..78d47945
--- /dev/null
+++ b/utils/test/bdaddr.8
@@ -0,0 +1,68 @@
+.TH BDADDR 8 "Sep 27 2005" BlueZ "Linux System Administration"
+.SH NAME
+bdaddr \- Utility for changing the Bluetooth device address
+.SH SYNOPSIS
+.B bdaddr
+.br
+.B bdaddr -h
+.br
+.B bdaddr [-i <dev>] [-r] [-t] [new bdaddr]
+
+.SH DESCRIPTION
+.LP
+.B
+bdaddr
+is used to query or set the local Bluetooth device address (BD_ADDR). If run
+with no arguments,
+.B
+bdaddr
+prints the chip manufacturer's name, and the current BD_ADDR. If the IEEE OUI
+index file "oui.txt" is installed on the system, the BD_ADDR owner will be
+displayed. If the optional [new bdaddr] argument is given, the device will be
+reprogrammed with that address. This can either be permanent or temporary, as
+specified by the -t flag. In both cases, the device must be reset before the
+new address will become active. This can be done with a 'soft' reset by
+specifying the -r flag, or a 'hard' reset by removing and replugging the
+device. A 'hard' reset will cause the address to revert to the current
+non-volatile value.
+.PP
+.B
+bdaddr
+uses manufacturer specific commands to set the address, and is therefore
+device specific. For this reason, not all devices are supported, and not all
+options are supported on all devices.
+Current supported manufacturers are:
+.B Ericsson, Cambridge Silicon Radio (CSR), Texas Instruments (TI), Zeevo
+and
+.B ST Microelectronics (ST)
+
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible commands.
+.TP
+.BI -i\ <dev>
+Specify a particular device to operate on. If not specified, default is the
+first available device.
+.TP
+.BI -r
+Reset device and make new BD_ADDR active.
+.B
+CSR
+devices only.
+.TP
+.BI -t
+Temporary change. Do not write to non-volatile memory.
+.B
+CSR
+devices only.
+.SH FILES
+.TP
+.I
+/usr/share/misc/oui.txt
+IEEE Organizationally Unique Identifier master file.
+Manually update from: http://standards.ieee.org/regauth/oui/oui.txt
+.SH AUTHORS
+Written by Marcel Holtmann <marcel@holtmann.org>,
+man page by Adam Laurie <adam@algroup.co.uk>
+.PP
diff --git a/utils/test/bdaddr.c b/utils/test/bdaddr.c
new file mode 100644
index 00000000..7c0df31d
--- /dev/null
+++ b/utils/test/bdaddr.c
@@ -0,0 +1,460 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "oui.h"
+
+static int transient = 0;
+
+static int generic_reset_device(int dd)
+{
+ bdaddr_t bdaddr;
+ int err;
+
+ err = hci_send_cmd(dd, 0x03, 0x0003, 0, NULL);
+ if (err < 0)
+ return err;
+
+ return hci_read_bd_addr(dd, &bdaddr, 10000);
+}
+
+#define OCF_ERICSSON_WRITE_BD_ADDR 0x000d
+typedef struct {
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) ericsson_write_bd_addr_cp;
+#define ERICSSON_WRITE_BD_ADDR_CP_SIZE 6
+
+static int ericsson_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+ struct hci_request rq;
+ ericsson_write_bd_addr_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, bdaddr);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = OCF_ERICSSON_WRITE_BD_ADDR;
+ rq.cparam = &cp;
+ rq.clen = ERICSSON_WRITE_BD_ADDR_CP_SIZE;
+ rq.rparam = NULL;
+ rq.rlen = 0;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ return 0;
+}
+
+#define OCF_ERICSSON_STORE_IN_FLASH 0x0022
+typedef struct {
+ uint8_t user_id;
+ uint8_t flash_length;
+ uint8_t flash_data[253];
+} __attribute__ ((packed)) ericsson_store_in_flash_cp;
+#define ERICSSON_STORE_IN_FLASH_CP_SIZE 255
+
+static int ericsson_store_in_flash(int dd, uint8_t user_id, uint8_t flash_length, uint8_t *flash_data)
+{
+ struct hci_request rq;
+ ericsson_store_in_flash_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.user_id = user_id;
+ cp.flash_length = flash_length;
+ if (flash_length > 0)
+ memcpy(cp.flash_data, flash_data, flash_length);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = OCF_ERICSSON_STORE_IN_FLASH;
+ rq.cparam = &cp;
+ rq.clen = ERICSSON_STORE_IN_FLASH_CP_SIZE;
+ rq.rparam = NULL;
+ rq.rlen = 0;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int csr_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+ unsigned char cmd[] = { 0x02, 0x00, 0x0c, 0x00, 0x11, 0x47, 0x03, 0x70,
+ 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ if (transient)
+ cmd[14] = 0x08;
+
+ cmd[16] = bdaddr->b[2];
+ cmd[17] = 0x00;
+ cmd[18] = bdaddr->b[0];
+ cmd[19] = bdaddr->b[1];
+ cmd[20] = bdaddr->b[3];
+ cmd[21] = 0x00;
+ cmd[22] = bdaddr->b[4];
+ cmd[23] = bdaddr->b[5];
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int csr_reset_device(int dd)
+{
+ unsigned char cmd[] = { 0x02, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ if (transient)
+ cmd[6] = 0x02;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ return 0;
+}
+
+#define OCF_TI_WRITE_BD_ADDR 0x0006
+typedef struct {
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) ti_write_bd_addr_cp;
+#define TI_WRITE_BD_ADDR_CP_SIZE 6
+
+static int ti_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+ struct hci_request rq;
+ ti_write_bd_addr_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, bdaddr);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = OCF_TI_WRITE_BD_ADDR;
+ rq.cparam = &cp;
+ rq.clen = TI_WRITE_BD_ADDR_CP_SIZE;
+ rq.rparam = NULL;
+ rq.rlen = 0;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ return 0;
+}
+
+#define OCF_BCM_WRITE_BD_ADDR 0x0001
+typedef struct {
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) bcm_write_bd_addr_cp;
+#define BCM_WRITE_BD_ADDR_CP_SIZE 6
+
+static int bcm_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+ struct hci_request rq;
+ bcm_write_bd_addr_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, bdaddr);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = OCF_BCM_WRITE_BD_ADDR;
+ rq.cparam = &cp;
+ rq.clen = BCM_WRITE_BD_ADDR_CP_SIZE;
+ rq.rparam = NULL;
+ rq.rlen = 0;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ return 0;
+}
+
+#define OCF_ZEEVO_WRITE_BD_ADDR 0x0001
+typedef struct {
+ bdaddr_t bdaddr;
+} __attribute__ ((packed)) zeevo_write_bd_addr_cp;
+#define ZEEVO_WRITE_BD_ADDR_CP_SIZE 6
+
+static int zeevo_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+ struct hci_request rq;
+ zeevo_write_bd_addr_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.bdaddr, bdaddr);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = OCF_ZEEVO_WRITE_BD_ADDR;
+ rq.cparam = &cp;
+ rq.clen = ZEEVO_WRITE_BD_ADDR_CP_SIZE;
+ rq.rparam = NULL;
+ rq.rlen = 0;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int st_write_bd_addr(int dd, bdaddr_t *bdaddr)
+{
+ return ericsson_store_in_flash(dd, 0xfe, 6, (uint8_t *) bdaddr);
+}
+
+static struct {
+ uint16_t compid;
+ int (*write_bd_addr)(int dd, bdaddr_t *bdaddr);
+ int (*reset_device)(int dd);
+} vendor[] = {
+ { 0, ericsson_write_bd_addr, NULL },
+ { 10, csr_write_bd_addr, csr_reset_device },
+ { 13, ti_write_bd_addr, NULL },
+ { 15, bcm_write_bd_addr, generic_reset_device },
+ { 18, zeevo_write_bd_addr, NULL },
+ { 48, st_write_bd_addr, generic_reset_device },
+ { 57, ericsson_write_bd_addr, generic_reset_device },
+ { 65535, NULL, NULL },
+};
+
+static void usage(void)
+{
+ printf("bdaddr - Utility for changing the Bluetooth device address\n\n");
+ printf("Usage:\n"
+ "\tbdaddr [-i <dev>] [-r] [-t] [new bdaddr]\n");
+}
+
+static struct option main_options[] = {
+ { "device", 1, 0, 'i' },
+ { "reset", 0, 0, 'r' },
+ { "transient", 0, 0, 't' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct hci_dev_info di;
+ struct hci_version ver;
+ bdaddr_t bdaddr;
+ char addr[18], oui[9], *comp;
+ int i, dd, opt, dev = 0, reset = 0;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt=getopt_long(argc, argv, "+i:rth", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'i':
+ dev = hci_devid(optarg);
+ if (dev < 0) {
+ perror("Invalid device");
+ exit(1);
+ }
+ break;
+
+ case 'r':
+ reset = 1;
+ break;
+
+ case 't':
+ transient = 1;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ dd = hci_open_dev(dev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (hci_devinfo(dev, &di) < 0) {
+ fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ exit(1);
+ }
+
+ if (hci_read_local_version(dd, &ver, 1000) < 0) {
+ fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ exit(1);
+ }
+
+ if (!bacmp(&di.bdaddr, BDADDR_ANY)) {
+ if (hci_read_bd_addr(dd, &bdaddr, 1000) < 0) {
+ fprintf(stderr, "Can't read address for hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ exit(1);
+ }
+ } else
+ bacpy(&bdaddr, &di.bdaddr);
+
+ printf("Manufacturer: %s (%d)\n",
+ bt_compidtostr(ver.manufacturer), ver.manufacturer);
+
+ ba2oui(&bdaddr, oui);
+ comp = ouitocomp(oui);
+
+ ba2str(&bdaddr, addr);
+ printf("Device address: %s", addr);
+
+ if (comp) {
+ printf(" (%s)\n", comp);
+ free(comp);
+ } else
+ printf("\n");
+
+ if (argc < 1) {
+ hci_close_dev(dd);
+ exit(0);
+ }
+
+ str2ba(argv[0], &bdaddr);
+ if (!bacmp(&bdaddr, BDADDR_ANY)) {
+ hci_close_dev(dd);
+ exit(0);
+ }
+
+ for (i = 0; vendor[i].compid != 65535; i++)
+ if (ver.manufacturer == vendor[i].compid) {
+ ba2oui(&bdaddr, oui);
+ comp = ouitocomp(oui);
+
+ ba2str(&bdaddr, addr);
+ printf("New BD address: %s", addr);
+
+ if (comp) {
+ printf(" (%s)\n\n", comp);
+ free(comp);
+ } else
+ printf("\n\n");
+
+
+ if (vendor[i].write_bd_addr(dd, &bdaddr) < 0) {
+ fprintf(stderr, "Can't write new address\n");
+ hci_close_dev(dd);
+ exit(1);
+ }
+
+ printf("Address changed - ");
+
+ if (reset && vendor[i].reset_device) {
+ if (vendor[i].reset_device(dd) < 0) {
+ printf("Reset device manually\n");
+ } else {
+ ioctl(dd, HCIDEVRESET, dev);
+ printf("Device reset successully\n");
+ }
+ } else {
+ printf("Reset device now\n");
+ }
+
+ //ioctl(dd, HCIDEVRESET, dev);
+ //ioctl(dd, HCIDEVDOWN, dev);
+ //ioctl(dd, HCIDEVUP, dev);
+
+ hci_close_dev(dd);
+ exit(0);
+ }
+
+ hci_close_dev(dd);
+
+ printf("\n");
+ fprintf(stderr, "Unsupported manufacturer\n");
+
+ exit(1);
+}
diff --git a/utils/test/dbusdef.py b/utils/test/dbusdef.py
new file mode 100644
index 00000000..ca6debf4
--- /dev/null
+++ b/utils/test/dbusdef.py
@@ -0,0 +1,59 @@
+import dbus
+
+bus = dbus.SystemBus()
+
+
+dummy = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'), 'org.freedesktop.DBus.Introspectable')
+
+#print dummy.Introspect()
+
+
+manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'), 'org.bluez.Manager')
+
+database = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'), 'org.bluez.Database')
+
+
+try:
+ adapter = dbus.Interface(bus.get_object('org.bluez', manager.DefaultAdapter()), 'org.bluez.Adapter')
+
+ test = dbus.Interface(bus.get_object('org.bluez', manager.DefaultAdapter()), 'org.bluez.Test')
+
+ rfcomm = dbus.Interface(bus.get_object('org.bluez', manager.DefaultAdapter()), 'org.bluez.RFCOMM')
+except:
+ adapter = ""
+
+ test = ""
+
+ rfcomm = ""
+
+
+def create_service(identifier):
+ try:
+ path = manager.FindService(identifier)
+ except:
+ path = ""
+
+ if (path != ""):
+ return dbus.Interface(bus.get_object('org.bluez', path), 'org.bluez.Service')
+
+echo = create_service("echo")
+
+transfer = create_service("transfer")
+
+network = create_service("network")
+
+input = create_service("input")
+
+audio = create_service("audio")
+
+headset = create_service("headset")
+
+
+def connect_service(identifier):
+ try:
+ conn = manager.ActivateService(identifier)
+ except:
+ conn = ""
+
+ if (conn != ""):
+ return dbus.Interface(bus.get_object(conn, "/org/bluez/" + identifier), 'org.bluez.' + identifier + '.Manager')
diff --git a/utils/test/hciemu.c b/utils/test/hciemu.c
new file mode 100644
index 00000000..bebcd9c8
--- /dev/null
+++ b/utils/test/hciemu.c
@@ -0,0 +1,1346 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/resource.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <netdb.h>
+
+#include <glib.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline uint64_t ntoh64(uint64_t n)
+{
+ uint64_t h;
+ uint64_t tmp = ntohl(n & 0x00000000ffffffff);
+ h = ntohl(n >> 32);
+ h |= tmp << 32;
+ return h;
+}
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define ntoh64(x) (x)
+#else
+#error "Unknown byte order"
+#endif
+#define hton64(x) ntoh64(x)
+
+#define GHCI_DEV "/dev/ghci"
+
+#define VHCI_DEV "/dev/vhci"
+#define VHCI_UDEV "/dev/hci_vhci"
+
+#define VHCI_MAX_CONN 12
+
+#define VHCI_ACL_MTU 192
+#define VHCI_ACL_MAX_PKT 8
+
+struct vhci_device {
+ uint8_t features[8];
+ uint8_t name[248];
+ uint8_t dev_class[3];
+ uint8_t inq_mode;
+ uint8_t eir_fec;
+ uint8_t eir_data[240];
+ uint16_t acl_cnt;
+ bdaddr_t bdaddr;
+ int fd;
+ int dd;
+ GIOChannel *scan;
+};
+
+struct vhci_conn {
+ bdaddr_t dest;
+ uint16_t handle;
+ GIOChannel *chan;
+};
+
+struct vhci_link_info {
+ bdaddr_t bdaddr;
+ uint8_t dev_class[3];
+ uint8_t link_type;
+ uint8_t role;
+} __attribute__ ((packed));
+
+static struct vhci_device vdev;
+static struct vhci_conn *vconn[VHCI_MAX_CONN];
+
+struct btsnoop_hdr {
+ uint8_t id[8]; /* Identification Pattern */
+ uint32_t version; /* Version Number = 1 */
+ uint32_t type; /* Datalink Type */
+} __attribute__ ((packed));
+#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
+
+struct btsnoop_pkt {
+ uint32_t size; /* Original Length */
+ uint32_t len; /* Included Length */
+ uint32_t flags; /* Packet Flags */
+ uint32_t drops; /* Cumulative Drops */
+ uint64_t ts; /* Timestamp microseconds */
+ uint8_t data[0]; /* Packet Data */
+} __attribute__ ((packed));
+#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
+
+static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
+
+static GMainLoop *event_loop;
+
+static volatile sig_atomic_t __io_canceled;
+
+static inline void io_init(void)
+{
+ __io_canceled = 0;
+}
+
+static inline void io_cancel(void)
+{
+ __io_canceled = 1;
+}
+
+static void sig_term(int sig)
+{
+ io_cancel();
+ g_main_loop_quit(event_loop);
+}
+
+static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data);
+static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data);
+static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data);
+
+static inline int read_n(int fd, void *buf, int len)
+{
+ register int w, t = 0;
+
+ while (!__io_canceled && len > 0) {
+ if ((w = read(fd, buf, len)) < 0 ){
+ if( errno == EINTR || errno == EAGAIN )
+ continue;
+ return -1;
+ }
+ if (!w)
+ return 0;
+ len -= w; buf += w; t += w;
+ }
+ return t;
+}
+
+/* Write exactly len bytes (Signal safe)*/
+static inline int write_n(int fd, void *buf, int len)
+{
+ register int w, t = 0;
+
+ while (!__io_canceled && len > 0) {
+ if ((w = write(fd, buf, len)) < 0 ){
+ if( errno == EINTR || errno == EAGAIN )
+ continue;
+ return -1;
+ }
+ if (!w)
+ return 0;
+ len -= w; buf += w; t += w;
+ }
+ return t;
+}
+
+static int create_snoop(char *file)
+{
+ struct btsnoop_hdr hdr;
+ int fd, len;
+
+ fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ return fd;
+
+ memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
+ hdr.version = htonl(1);
+ hdr.type = htonl(1002);
+
+ len = write(fd, &hdr, BTSNOOP_HDR_SIZE);
+ if (len < 0) {
+ close(fd);
+ return -EIO;
+ }
+
+ if (len != BTSNOOP_HDR_SIZE) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static int write_snoop(int fd, int type, int incoming, unsigned char *buf, int len)
+{
+ struct btsnoop_pkt pkt;
+ struct timeval tv;
+ uint32_t size = len;
+ uint64_t ts;
+ int err;
+
+ if (fd < 0)
+ return -1;
+
+ memset(&tv, 0, sizeof(tv));
+ gettimeofday(&tv, NULL);
+ ts = (tv.tv_sec - 946684800ll) * 1000000ll + tv.tv_usec;
+
+ pkt.size = htonl(size);
+ pkt.len = pkt.size;
+ pkt.flags = ntohl(incoming & 0x01);
+ pkt.drops = htonl(0);
+ pkt.ts = hton64(ts + 0x00E03AB44A676000ll);
+
+ if (type == HCI_COMMAND_PKT || type == HCI_EVENT_PKT)
+ pkt.flags |= ntohl(0x02);
+
+ err = write(fd, &pkt, BTSNOOP_PKT_SIZE);
+ err = write(fd, buf, size);
+
+ return 0;
+}
+
+static struct vhci_conn *conn_get_by_bdaddr(bdaddr_t *ba)
+{
+ register int i;
+
+ for (i = 0; i < VHCI_MAX_CONN; i++)
+ if (!bacmp(&vconn[i]->dest, ba))
+ return vconn[i];
+
+ return NULL;
+}
+
+static void command_status(uint16_t ogf, uint16_t ocf, uint8_t status)
+{
+ uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
+ evt_cmd_status *cs;
+ hci_event_hdr *he;
+
+ /* Packet type */
+ *ptr++ = HCI_EVENT_PKT;
+
+ /* Event header */
+ he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
+
+ he->evt = EVT_CMD_STATUS;
+ he->plen = EVT_CMD_STATUS_SIZE;
+
+ cs = (void *) ptr; ptr += EVT_CMD_STATUS_SIZE;
+
+ cs->status = status;
+ cs->ncmd = 1;
+ cs->opcode = htobs(cmd_opcode_pack(ogf, ocf));
+
+ write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
+
+ if (write(vdev.fd, buf, ptr - buf) < 0)
+ syslog(LOG_ERR, "Can't send event: %s(%d)",
+ strerror(errno), errno);
+}
+
+static void command_complete(uint16_t ogf, uint16_t ocf, int plen, void *data)
+{
+ uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
+ evt_cmd_complete *cc;
+ hci_event_hdr *he;
+
+ /* Packet type */
+ *ptr++ = HCI_EVENT_PKT;
+
+ /* Event header */
+ he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
+
+ he->evt = EVT_CMD_COMPLETE;
+ he->plen = EVT_CMD_COMPLETE_SIZE + plen;
+
+ cc = (void *) ptr; ptr += EVT_CMD_COMPLETE_SIZE;
+
+ cc->ncmd = 1;
+ cc->opcode = htobs(cmd_opcode_pack(ogf, ocf));
+
+ if (plen) {
+ memcpy(ptr, data, plen);
+ ptr += plen;
+ }
+
+ write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
+
+ if (write(vdev.fd, buf, ptr - buf) < 0)
+ syslog(LOG_ERR, "Can't send event: %s(%d)",
+ strerror(errno), errno);
+}
+
+static void connect_request(struct vhci_conn *conn)
+{
+ uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
+ evt_conn_request *cr;
+ hci_event_hdr *he;
+
+ /* Packet type */
+ *ptr++ = HCI_EVENT_PKT;
+
+ /* Event header */
+ he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
+
+ he->evt = EVT_CONN_REQUEST;
+ he->plen = EVT_CONN_REQUEST_SIZE;
+
+ cr = (void *) ptr; ptr += EVT_CONN_REQUEST_SIZE;
+
+ bacpy(&cr->bdaddr, &conn->dest);
+ memset(&cr->dev_class, 0, sizeof(cr->dev_class));
+ cr->link_type = ACL_LINK;
+
+ write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
+
+ if (write(vdev.fd, buf, ptr - buf) < 0)
+ syslog(LOG_ERR, "Can't send event: %s (%d)",
+ strerror(errno), errno);
+}
+
+static void connect_complete(struct vhci_conn *conn)
+{
+ uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
+ evt_conn_complete *cc;
+ hci_event_hdr *he;
+
+ /* Packet type */
+ *ptr++ = HCI_EVENT_PKT;
+
+ /* Event header */
+ he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
+
+ he->evt = EVT_CONN_COMPLETE;
+ he->plen = EVT_CONN_COMPLETE_SIZE;
+
+ cc = (void *) ptr; ptr += EVT_CONN_COMPLETE_SIZE;
+
+ bacpy(&cc->bdaddr, &conn->dest);
+ cc->status = 0x00;
+ cc->handle = htobs(conn->handle);
+ cc->link_type = ACL_LINK;
+ cc->encr_mode = 0x00;
+
+ write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
+
+ if (write(vdev.fd, buf, ptr - buf) < 0)
+ syslog(LOG_ERR, "Can't send event: %s (%d)",
+ strerror(errno), errno);
+}
+
+static void disconn_complete(struct vhci_conn *conn)
+{
+ uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
+ evt_disconn_complete *dc;
+ hci_event_hdr *he;
+
+ /* Packet type */
+ *ptr++ = HCI_EVENT_PKT;
+
+ /* Event header */
+ he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
+
+ he->evt = EVT_DISCONN_COMPLETE;
+ he->plen = EVT_DISCONN_COMPLETE_SIZE;
+
+ dc = (void *) ptr; ptr += EVT_DISCONN_COMPLETE_SIZE;
+
+ dc->status = 0x00;
+ dc->handle = htobs(conn->handle);
+ dc->reason = 0x00;
+
+ write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
+
+ if (write(vdev.fd, buf, ptr - buf) < 0)
+ syslog(LOG_ERR, "Can't send event: %s (%d)",
+ strerror(errno), errno);
+
+ vdev.acl_cnt = 0;
+}
+
+static void num_completed_pkts(struct vhci_conn *conn)
+{
+ uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
+ evt_num_comp_pkts *np;
+ hci_event_hdr *he;
+
+ /* Packet type */
+ *ptr++ = HCI_EVENT_PKT;
+
+ /* Event header */
+ he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
+
+ he->evt = EVT_NUM_COMP_PKTS;
+ he->plen = EVT_NUM_COMP_PKTS_SIZE;
+
+ np = (void *) ptr; ptr += EVT_NUM_COMP_PKTS_SIZE;
+ np->num_hndl = 1;
+
+ *((uint16_t *) ptr) = htobs(conn->handle); ptr += 2;
+ *((uint16_t *) ptr) = htobs(vdev.acl_cnt); ptr += 2;
+
+ write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
+
+ if (write(vdev.fd, buf, ptr - buf) < 0)
+ syslog(LOG_ERR, "Can't send event: %s (%d)",
+ strerror(errno), errno);
+}
+
+static int scan_enable(uint8_t *data)
+{
+ struct sockaddr_in sa;
+ GIOChannel *sk_io;
+ bdaddr_t ba;
+ int sk, opt;
+
+ if (!(*data & SCAN_PAGE)) {
+ if (vdev.scan) {
+ g_io_channel_close(vdev.scan);
+ vdev.scan = NULL;
+ }
+ return 0;
+ }
+
+ if (vdev.scan)
+ return 0;
+
+ if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ return 1;
+ }
+
+ opt = 1;
+ setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+ baswap(&ba, &vdev.bdaddr);
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = *(uint32_t *) &ba;
+ sa.sin_port = *(uint16_t *) &ba.b[4];
+ if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ goto failed;
+ }
+
+ if (listen(sk, 10)) {
+ syslog(LOG_ERR, "Can't listen on socket: %s (%d)",
+ strerror(errno), errno);
+ goto failed;
+ }
+
+ sk_io = g_io_channel_unix_new(sk);
+ g_io_add_watch(sk_io, G_IO_IN | G_IO_NVAL, io_conn_ind, NULL);
+ vdev.scan = sk_io;
+ return 0;
+
+failed:
+ close(sk);
+ return 1;
+}
+
+static void accept_connection(uint8_t *data)
+{
+ accept_conn_req_cp *cp = (void *) data;
+ struct vhci_conn *conn;
+
+ if (!(conn = conn_get_by_bdaddr(&cp->bdaddr)))
+ return;
+
+ connect_complete(conn);
+
+ g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,
+ io_acl_data, (gpointer) conn);
+}
+
+static void close_connection(struct vhci_conn *conn)
+{
+ syslog(LOG_INFO, "Closing connection %s handle %d",
+ batostr(&conn->dest), conn->handle);
+
+ g_io_channel_close(conn->chan);
+ g_io_channel_unref(conn->chan);
+
+ vconn[conn->handle - 1] = NULL;
+ disconn_complete(conn);
+ free(conn);
+}
+
+static void disconnect(uint8_t *data)
+{
+ disconnect_cp *cp = (void *) data;
+ struct vhci_conn *conn;
+ uint16_t handle;
+
+ handle = btohs(cp->handle);
+
+ if (handle - 1 > VHCI_MAX_CONN)
+ return;
+
+ if (!(conn = vconn[handle-1]))
+ return;
+
+ close_connection(conn);
+}
+
+static void create_connection(uint8_t *data)
+{
+ create_conn_cp *cp = (void *) data;
+ struct vhci_link_info info;
+ struct vhci_conn *conn;
+ struct sockaddr_in sa;
+ int h, sk, opt;
+ bdaddr_t ba;
+
+ for (h = 0; h < VHCI_MAX_CONN; h++)
+ if (!vconn[h])
+ goto do_connect;
+
+ syslog(LOG_ERR, "Too many connections");
+ return;
+
+do_connect:
+ if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ return;
+ }
+
+ opt = 1;
+ setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+ baswap(&ba, &vdev.bdaddr);
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = INADDR_ANY; // *(uint32_t *) &ba;
+ sa.sin_port = 0; // *(uint16_t *) &ba.b[4];
+ if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ close(sk);
+ return;
+ }
+
+ baswap(&ba, &cp->bdaddr);
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = *(uint32_t *) &ba;
+ sa.sin_port = *(uint16_t *) &ba.b[4];
+ if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ syslog(LOG_ERR, "Can't connect: %s (%d)",
+ strerror(errno), errno);
+ close(sk);
+ return;
+ }
+
+ /* Send info */
+ memset(&info, 0, sizeof(info));
+ bacpy(&info.bdaddr, &vdev.bdaddr);
+ info.link_type = ACL_LINK;
+ info.role = 1;
+ write_n(sk, (void *) &info, sizeof(info));
+
+ if (!(conn = malloc(sizeof(*conn)))) {
+ syslog(LOG_ERR, "Can't alloc new connection: %s (%d)",
+ strerror(errno), errno);
+ close(sk);
+ return;
+ }
+
+ memcpy((uint8_t *) &ba, (uint8_t *) &sa.sin_addr, 4);
+ memcpy((uint8_t *) &ba.b[4], (uint8_t *) &sa.sin_port, 2);
+ baswap(&conn->dest, &ba);
+
+ vconn[h] = conn;
+ conn->handle = h + 1;
+ conn->chan = g_io_channel_unix_new(sk);
+
+ connect_complete(conn);
+ g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,
+ io_acl_data, (gpointer) conn);
+ return;
+}
+
+static void inline hci_link_control(uint16_t ocf, int plen, uint8_t *data)
+{
+ uint8_t status;
+
+ const uint16_t ogf = OGF_LINK_CTL;
+
+ switch (ocf) {
+ case OCF_CREATE_CONN:
+ command_status(ogf, ocf, 0x00);
+ create_connection(data);
+ break;
+
+ case OCF_ACCEPT_CONN_REQ:
+ command_status(ogf, ocf, 0x00);
+ accept_connection(data);
+ break;
+
+ case OCF_DISCONNECT:
+ command_status(ogf, ocf, 0x00);
+ disconnect(data);
+ break;
+
+ default:
+ status = 0x01;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+ }
+}
+
+static void inline hci_link_policy(uint16_t ocf, int plen, uint8_t *data)
+{
+ uint8_t status;
+
+ const uint16_t ogf = OGF_INFO_PARAM;
+
+ switch (ocf) {
+ default:
+ status = 0x01;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+ }
+}
+
+static void inline hci_host_control(uint16_t ocf, int plen, uint8_t *data)
+{
+ read_local_name_rp ln;
+ read_class_of_dev_rp cd;
+ read_inquiry_mode_rp im;
+ read_ext_inquiry_response_rp ir;
+ uint8_t status;
+
+ const uint16_t ogf = OGF_HOST_CTL;
+
+ switch (ocf) {
+ case OCF_RESET:
+ status = 0x00;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_SET_EVENT_FLT:
+ status = 0x00;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_CHANGE_LOCAL_NAME:
+ status = 0x00;
+ memcpy(vdev.name, data, sizeof(vdev.name));
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_READ_LOCAL_NAME:
+ ln.status = 0x00;
+ memcpy(ln.name, vdev.name, sizeof(ln.name));
+ command_complete(ogf, ocf, sizeof(ln), &ln);
+ break;
+
+ case OCF_WRITE_CONN_ACCEPT_TIMEOUT:
+ case OCF_WRITE_PAGE_TIMEOUT:
+ status = 0x00;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_WRITE_SCAN_ENABLE:
+ status = scan_enable(data);
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_WRITE_AUTH_ENABLE:
+ status = 0x00;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_WRITE_ENCRYPT_MODE:
+ status = 0x00;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_READ_CLASS_OF_DEV:
+ cd.status = 0x00;
+ memcpy(cd.dev_class, vdev.dev_class, 3);
+ command_complete(ogf, ocf, sizeof(cd), &cd);
+ break;
+
+ case OCF_WRITE_CLASS_OF_DEV:
+ status = 0x00;
+ memcpy(vdev.dev_class, data, 3);
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_READ_INQUIRY_MODE:
+ im.status = 0x00;
+ im.mode = vdev.inq_mode;
+ command_complete(ogf, ocf, sizeof(im), &im);
+ break;
+
+ case OCF_WRITE_INQUIRY_MODE:
+ status = 0x00;
+ vdev.inq_mode = data[0];
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ case OCF_READ_EXT_INQUIRY_RESPONSE:
+ ir.status = 0x00;
+ ir.fec = vdev.eir_fec;
+ memcpy(ir.data, vdev.eir_data, 240);
+ command_complete(ogf, ocf, sizeof(ir), &ir);
+ break;
+
+ case OCF_WRITE_EXT_INQUIRY_RESPONSE:
+ status = 0x00;
+ vdev.eir_fec = data[0];
+ memcpy(vdev.eir_data, data + 1, 240);
+ command_complete(ogf, ocf, 1, &status);
+ break;
+
+ default:
+ status = 0x01;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+ }
+}
+
+static void inline hci_info_param(uint16_t ocf, int plen, uint8_t *data)
+{
+ read_local_version_rp lv;
+ read_local_features_rp lf;
+ read_local_ext_features_rp ef;
+ read_buffer_size_rp bs;
+ read_bd_addr_rp ba;
+ uint8_t status;
+
+ const uint16_t ogf = OGF_INFO_PARAM;
+
+ switch (ocf) {
+ case OCF_READ_LOCAL_VERSION:
+ lv.status = 0x00;
+ lv.hci_ver = 0x03;
+ lv.hci_rev = htobs(0x0000);
+ lv.lmp_ver = 0x03;
+ lv.manufacturer = htobs(29);
+ lv.lmp_subver = htobs(0x0000);
+ command_complete(ogf, ocf, sizeof(lv), &lv);
+ break;
+
+ case OCF_READ_LOCAL_FEATURES:
+ lf.status = 0x00;
+ memcpy(lf.features, vdev.features, 8);
+ command_complete(ogf, ocf, sizeof(lf), &lf);
+ break;
+
+ case OCF_READ_LOCAL_EXT_FEATURES:
+ ef.status = 0x00;
+ if (*data == 0) {
+ ef.page_num = 0;
+ ef.max_page_num = 0;
+ memcpy(ef.features, vdev.features, 8);
+ } else {
+ ef.page_num = *data;
+ ef.max_page_num = 0;
+ memset(ef.features, 0, 8);
+ }
+ command_complete(ogf, ocf, sizeof(ef), &ef);
+ break;
+
+ case OCF_READ_BUFFER_SIZE:
+ bs.status = 0x00;
+ bs.acl_mtu = htobs(VHCI_ACL_MTU);
+ bs.sco_mtu = 0;
+ bs.acl_max_pkt = htobs(VHCI_ACL_MAX_PKT);
+ bs.sco_max_pkt = htobs(0);
+ command_complete(ogf, ocf, sizeof(bs), &bs);
+ break;
+
+ case OCF_READ_BD_ADDR:
+ ba.status = 0x00;
+ bacpy(&ba.bdaddr, &vdev.bdaddr);
+ command_complete(ogf, ocf, sizeof(ba), &ba);
+ break;
+
+ default:
+ status = 0x01;
+ command_complete(ogf, ocf, 1, &status);
+ break;
+ }
+}
+
+static void hci_command(uint8_t *data)
+{
+ hci_command_hdr *ch;
+ uint8_t *ptr = data;
+ uint16_t ogf, ocf;
+
+ ch = (hci_command_hdr *) ptr;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ ch->opcode = btohs(ch->opcode);
+ ogf = cmd_opcode_ogf(ch->opcode);
+ ocf = cmd_opcode_ocf(ch->opcode);
+
+ switch (ogf) {
+ case OGF_LINK_CTL:
+ hci_link_control(ocf, ch->plen, ptr);
+ break;
+
+ case OGF_LINK_POLICY:
+ hci_link_policy(ocf, ch->plen, ptr);
+ break;
+
+ case OGF_HOST_CTL:
+ hci_host_control(ocf, ch->plen, ptr);
+ break;
+
+ case OGF_INFO_PARAM:
+ hci_info_param(ocf, ch->plen, ptr);
+ break;
+ }
+}
+
+static void hci_acl_data(uint8_t *data)
+{
+ hci_acl_hdr *ah = (void *) data;
+ struct vhci_conn *conn;
+ uint16_t handle;
+ int fd;
+
+ handle = acl_handle(btohs(ah->handle));
+
+ if (handle > VHCI_MAX_CONN || !(conn = vconn[handle - 1])) {
+ syslog(LOG_ERR, "Bad connection handle %d", handle);
+ return;
+ }
+
+ fd = g_io_channel_unix_get_fd(conn->chan);
+ if (write_n(fd, data, btohs(ah->dlen) + HCI_ACL_HDR_SIZE) < 0) {
+ close_connection(conn);
+ return;
+ }
+
+ if (++vdev.acl_cnt > VHCI_ACL_MAX_PKT - 1) {
+ /* Send num of complete packets event */
+ num_completed_pkts(conn);
+ vdev.acl_cnt = 0;
+ }
+}
+
+static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct vhci_conn *conn = (struct vhci_conn *) data;
+ unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
+ hci_acl_hdr *ah;
+ uint16_t flags;
+ int fd, err, len;
+
+ if (cond & G_IO_NVAL) {
+ g_io_channel_unref(chan);
+ return FALSE;
+ }
+
+ if (cond & G_IO_HUP) {
+ close_connection(conn);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(chan);
+
+ ptr = buf + 1;
+ if (read_n(fd, ptr, HCI_ACL_HDR_SIZE) <= 0) {
+ close_connection(conn);
+ return FALSE;
+ }
+
+ ah = (void *) ptr;
+ ptr += HCI_ACL_HDR_SIZE;
+
+ len = btohs(ah->dlen);
+ if (read_n(fd, ptr, len) <= 0) {
+ close_connection(conn);
+ return FALSE;
+ }
+
+ buf[0] = HCI_ACLDATA_PKT;
+
+ flags = acl_flags(btohs(ah->handle));
+ ah->handle = htobs(acl_handle_pack(conn->handle, flags));
+ len += HCI_ACL_HDR_SIZE + 1;
+
+ write_snoop(vdev.dd, HCI_ACLDATA_PKT, 1, buf, len);
+
+ err = write(vdev.fd, buf, len);
+
+ return TRUE;
+}
+
+static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct vhci_link_info info;
+ struct vhci_conn *conn;
+ struct sockaddr_in sa;
+ socklen_t len;
+ int sk, nsk, h;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ len = sizeof(sa);
+ if ((nsk = accept(sk, (struct sockaddr *) &sa, &len)) < 0)
+ return TRUE;
+
+ if (read_n(nsk, &info, sizeof(info)) < 0) {
+ syslog(LOG_ERR, "Can't read link info");
+ return TRUE;
+ }
+
+ if (!(conn = malloc(sizeof(*conn)))) {
+ syslog(LOG_ERR, "Can't alloc new connection");
+ close(nsk);
+ return TRUE;
+ }
+
+ bacpy(&conn->dest, &info.bdaddr);
+
+ for (h = 0; h < VHCI_MAX_CONN; h++)
+ if (!vconn[h])
+ goto accepted;
+
+ syslog(LOG_ERR, "Too many connections");
+ free(conn);
+ close(nsk);
+ return TRUE;
+
+accepted:
+ vconn[h] = conn;
+ conn->handle = h + 1;
+ conn->chan = g_io_channel_unix_new(nsk);
+ connect_request(conn);
+
+ return TRUE;
+}
+
+static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
+ int type;
+ gsize len;
+ GIOError err;
+
+ ptr = buf;
+
+ if ((err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len))) {
+ if (err == G_IO_ERROR_AGAIN)
+ return TRUE;
+
+ syslog(LOG_ERR, "Read failed: %s (%d)", strerror(errno), errno);
+ g_io_channel_unref(chan);
+ g_main_loop_quit(event_loop);
+ return FALSE;
+ }
+
+ type = *ptr++;
+
+ write_snoop(vdev.dd, type, 0, buf, len);
+
+ switch (type) {
+ case HCI_COMMAND_PKT:
+ hci_command(ptr);
+ break;
+
+ case HCI_ACLDATA_PKT:
+ hci_acl_data(ptr);
+ break;
+
+ default:
+ syslog(LOG_ERR, "Unknown packet type 0x%2.2x", type);
+ break;
+ }
+
+ return TRUE;
+}
+
+static int getbdaddrbyname(char *str, bdaddr_t *ba)
+{
+ int i, n, len;
+
+ len = strlen(str);
+
+ /* Check address format */
+ for (i = 0, n = 0; i < len; i++)
+ if (str[i] == ':')
+ n++;
+
+ if (n == 5) {
+ /* BD address */
+ baswap(ba, strtoba(str));
+ return 0;
+ }
+
+ if (n == 1) {
+ /* IP address + port */
+ struct hostent *hent;
+ bdaddr_t b;
+ char *ptr;
+
+ ptr = strchr(str, ':');
+ *ptr++ = 0;
+
+ if (!(hent = gethostbyname(str))) {
+ fprintf(stderr, "Can't resolve %s\n", str);
+ return -2;
+ }
+
+ memcpy(&b, hent->h_addr, 4);
+ *(uint16_t *) (&b.b[4]) = htons(atoi(ptr));
+ baswap(ba, &b);
+
+ return 0;
+ }
+
+ fprintf(stderr, "Invalid address format\n");
+
+ return -1;
+}
+
+static void rewrite_bdaddr(unsigned char *buf, int len, bdaddr_t *bdaddr)
+{
+ hci_event_hdr *eh;
+ unsigned char *ptr = buf;
+ int type;
+
+ if (!bdaddr)
+ return;
+
+ if (!bacmp(bdaddr, BDADDR_ANY))
+ return;
+
+ type = *ptr++;
+
+ switch (type) {
+ case HCI_EVENT_PKT:
+ eh = (hci_event_hdr *) ptr;
+ ptr += HCI_EVENT_HDR_SIZE;
+
+ if (eh->evt == EVT_CMD_COMPLETE) {
+ evt_cmd_complete *cc = (void *) ptr;
+
+ ptr += EVT_CMD_COMPLETE_SIZE;
+
+ if (cc->opcode == htobs(cmd_opcode_pack(OGF_INFO_PARAM,
+ OCF_READ_BD_ADDR))) {
+ bacpy((bdaddr_t *) (ptr + 1), bdaddr);
+ }
+ }
+ break;
+ }
+}
+
+static int run_proxy(int fd, int dev, bdaddr_t *bdaddr)
+{
+ unsigned char buf[HCI_MAX_FRAME_SIZE + 1];
+ struct hci_dev_info di;
+ struct hci_filter flt;
+ struct pollfd p[2];
+ int dd, err, len, need_raw;
+
+ dd = hci_open_dev(dev);
+ if (dd < 0) {
+ syslog(LOG_ERR, "Can't open device hci%d: %s (%d)",
+ dev, strerror(errno), errno);
+ return 1;
+ }
+
+ if (hci_devinfo(dev, &di) < 0) {
+ syslog(LOG_ERR, "Can't get device info for hci%d: %s (%d)",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ return 1;
+ }
+
+ need_raw = !hci_test_bit(HCI_RAW, &di.flags);
+
+ hci_filter_clear(&flt);
+ hci_filter_all_ptypes(&flt);
+ hci_filter_all_events(&flt);
+
+ if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+ syslog(LOG_ERR, "Can't set filter for hci%d: %s (%d)",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ return 1;
+ }
+
+ if (need_raw) {
+ if (ioctl(dd, HCISETRAW, 1) < 0) {
+ syslog(LOG_ERR, "Can't set raw mode on hci%d: %s (%d)",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ return 1;
+ }
+ }
+
+ p[0].fd = fd;
+ p[0].events = POLLIN;
+ p[1].fd = dd;
+ p[1].events = POLLIN;
+
+ while (!__io_canceled) {
+ p[0].revents = 0;
+ p[1].revents = 0;
+ err = poll(p, 2, 500);
+ if (err < 0)
+ break;
+ if (!err)
+ continue;
+
+ if (p[0].revents & POLLIN) {
+ len = read(fd, buf, sizeof(buf));
+ if (len > 0) {
+ rewrite_bdaddr(buf, len, bdaddr);
+ err = write(dd, buf, len);
+ }
+ }
+
+ if (p[1].revents & POLLIN) {
+ len = read(dd, buf, sizeof(buf));
+ if (len > 0) {
+ rewrite_bdaddr(buf, len, bdaddr);
+ err = write(fd, buf, len);
+ }
+ }
+ }
+
+ if (need_raw) {
+ if (ioctl(dd, HCISETRAW, 0) < 0)
+ syslog(LOG_ERR, "Can't clear raw mode on hci%d: %s (%d)",
+ dev, strerror(errno), errno);
+ }
+
+ hci_close_dev(dd);
+
+ syslog(LOG_INFO, "Exit");
+
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("hciemu - HCI emulator ver %s\n", VERSION);
+ printf("Usage: \n");
+ printf("\thciemu [-n] local_address\n");
+}
+
+static struct option main_options[] = {
+ { "device", 1, 0, 'd' },
+ { "bdaddr", 1, 0, 'b' },
+ { "snoop", 1, 0, 's' },
+ { "nodetach", 0, 0, 'n' },
+ { "help", 0, 0, 'h' },
+ { 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ GIOChannel *dev_io;
+ char *device = NULL, *snoop = NULL;
+ bdaddr_t bdaddr;
+ int fd, dd, opt, detach = 1, dev = -1;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt=getopt_long(argc, argv, "d:b:s:nh", main_options, NULL)) != EOF) {
+ switch(opt) {
+ case 'd':
+ device = strdup(optarg);
+ break;
+
+ case 'b':
+ str2ba(optarg, &bdaddr);
+ break;
+
+ case 's':
+ snoop = strdup(optarg);
+ break;
+
+ case 'n':
+ detach = 0;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ if (strlen(argv[0]) > 3 && !strncasecmp(argv[0], "hci", 3)) {
+ dev = hci_devid(argv[0]);
+ if (dev < 0) {
+ perror("Invalid device");
+ exit(1);
+ }
+ } else {
+ if (getbdaddrbyname(argv[0], &vdev.bdaddr) < 0)
+ exit(1);
+ }
+
+ if (detach) {
+ if (daemon(0, 0)) {
+ perror("Can't start daemon");
+ exit(1);
+ }
+ }
+
+ /* Start logging to syslog and stderr */
+ openlog("hciemu", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
+ syslog(LOG_INFO, "HCI emulation daemon ver %s started", VERSION);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ io_init();
+
+ if (!device && dev >= 0)
+ device = strdup(GHCI_DEV);
+
+ /* Open and create virtual HCI device */
+ if (device) {
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ syslog(LOG_ERR, "Can't open device %s: %s (%d)",
+ device, strerror(errno), errno);
+ free(device);
+ exit(1);
+ }
+ free(device);
+ } else {
+ fd = open(VHCI_DEV, O_RDWR);
+ if (fd < 0) {
+ fd = open(VHCI_UDEV, O_RDWR);
+ if (fd < 0) {
+ syslog(LOG_ERR, "Can't open device %s: %s (%d)",
+ VHCI_DEV, strerror(errno), errno);
+ exit(1);
+ }
+ }
+ }
+
+ /* Create snoop file */
+ if (snoop) {
+ dd = create_snoop(snoop);
+ if (dd < 0)
+ syslog(LOG_ERR, "Can't create snoop file %s: %s (%d)",
+ snoop, strerror(errno), errno);
+ free(snoop);
+ } else
+ dd = -1;
+
+ /* Create event loop */
+ event_loop = g_main_loop_new(NULL, FALSE);
+
+ if (dev >= 0)
+ return run_proxy(fd, dev, &bdaddr);
+
+ /* Device settings */
+ vdev.features[0] = 0xff;
+ vdev.features[1] = 0xff;
+ vdev.features[2] = 0x8f;
+ vdev.features[3] = 0xfe;
+ vdev.features[4] = 0x9b;
+ vdev.features[5] = 0xf9;
+ vdev.features[6] = 0x01;
+ vdev.features[7] = 0x80;
+
+ memset(vdev.name, 0, sizeof(vdev.name));
+ strncpy((char *) vdev.name, "BlueZ (Virtual HCI)", sizeof(vdev.name));
+
+ vdev.dev_class[0] = 0x00;
+ vdev.dev_class[1] = 0x00;
+ vdev.dev_class[2] = 0x00;
+
+ vdev.inq_mode = 0x00;
+ vdev.eir_fec = 0x00;
+ memset(vdev.eir_data, 0, sizeof(vdev.eir_data));
+
+ vdev.fd = fd;
+ vdev.dd = dd;
+
+ dev_io = g_io_channel_unix_new(fd);
+ g_io_add_watch(dev_io, G_IO_IN, io_hci_data, NULL);
+
+ setpriority(PRIO_PROCESS, 0, -19);
+
+ /* Start event processor */
+ g_main_loop_run(event_loop);
+
+ close(fd);
+
+ if (dd >= 0)
+ close(dd);
+
+ syslog(LOG_INFO, "Exit");
+
+ return 0;
+}
diff --git a/utils/test/hsmicro b/utils/test/hsmicro
new file mode 100755
index 00000000..c254226b
--- /dev/null
+++ b/utils/test/hsmicro
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+SOX=`which sox`
+HSTEST=`which hstest`
+
+if [ -z "$HSTEST" ]
+then
+ HSTEST="./hstest"
+fi
+
+if [ -z "$1" ]
+then
+ echo -e "Usage:\n\thsmicro <bdaddr> [channel]"
+ exit
+fi
+
+BDADDR=$1
+CHANNEL=$2
+
+$HSTEST record - $BDADDR $CHANNEL | $SOX -t raw -r 8000 -c 1 -s -w - -t ossdsp -r 44100 -c 2 -s -w /dev/dsp polyphase vol 5.0 2> /dev/null
diff --git a/utils/test/hsplay b/utils/test/hsplay
new file mode 100755
index 00000000..8cecbffa
--- /dev/null
+++ b/utils/test/hsplay
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+MPG123=`which mpg123`
+SOX=`which sox`
+HSTEST=`which hstest`
+
+if [ -z "$HSTEST" ]
+then
+ HSTEST="./hstest"
+fi
+
+if [ -z "$1" ] || [ -z "$2" ]
+then
+ echo -e "Usage:\n\thsplay <file> <bdaddr> [channel]"
+ exit
+fi
+
+FILE=$1
+BDADDR=$2
+CHANNEL=$3
+
+$MPG123 -q -s "$FILE" | $SOX -t raw -r 44100 -c 2 -s -w - -t raw -r 8000 -c 1 -s -w - | $HSTEST play - $BDADDR $CHANNEL
diff --git a/utils/test/hstest.c b/utils/test/hstest.c
new file mode 100644
index 00000000..158bf204
--- /dev/null
+++ b/utils/test/hstest.c
@@ -0,0 +1,308 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/rfcomm.h>
+
+static volatile int terminate = 0;
+
+static void sig_term(int sig) {
+ terminate = 1;
+}
+
+static int rfcomm_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t channel)
+{
+ struct sockaddr_rc addr;
+ int s;
+
+ if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = 0;
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ close(s);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, dst);
+ addr.rc_channel = channel;
+ if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+static int sco_connect(bdaddr_t *src, bdaddr_t *dst, uint16_t *handle, uint16_t *mtu)
+{
+ struct sockaddr_sco addr;
+ struct sco_conninfo conn;
+ struct sco_options opts;
+ socklen_t size;
+ int s;
+
+ if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, src);
+
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ close(s);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, dst);
+
+ if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
+ close(s);
+ return -1;
+ }
+
+ memset(&conn, 0, sizeof(conn));
+ size = sizeof(conn);
+
+ if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) {
+ close(s);
+ return -1;
+ }
+
+ memset(&opts, 0, sizeof(opts));
+ size = sizeof(opts);
+
+ if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) {
+ close(s);
+ return -1;
+ }
+
+ if (handle)
+ *handle = conn.hci_handle;
+
+ if (mtu)
+ *mtu = opts.mtu;
+
+ return s;
+}
+
+static void usage(void)
+{
+ printf("Usage:\n"
+ "\thstest play <file> <bdaddr> [channel]\n"
+ "\thstest record <file> <bdaddr> [channel]\n");
+}
+
+#define PLAY 1
+#define RECORD 2
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+
+ fd_set rfds;
+ struct timeval timeout;
+ unsigned char buf[2048], *p;
+ int maxfd, sel, rlen, wlen;
+
+ bdaddr_t local;
+ bdaddr_t bdaddr;
+ uint8_t channel;
+
+ char *filename;
+ mode_t filemode;
+ int err, mode = 0;
+ int dd, rd, sd, fd;
+ uint16_t sco_handle, sco_mtu, vs;
+
+ switch (argc) {
+ case 4:
+ str2ba(argv[3], &bdaddr);
+ channel = 6;
+ break;
+ case 5:
+ str2ba(argv[3], &bdaddr);
+ channel = atoi(argv[4]);
+ break;
+ default:
+ usage();
+ exit(-1);
+ }
+
+ if (strncmp(argv[1], "play", 4) == 0) {
+ mode = PLAY;
+ filemode = O_RDONLY;
+ } else if (strncmp(argv[1], "rec", 3) == 0) {
+ mode = RECORD;
+ filemode = O_WRONLY | O_CREAT | O_TRUNC;
+ } else {
+ usage();
+ exit(-1);
+ }
+
+ filename = argv[2];
+
+ hci_devba(0, &local);
+ dd = hci_open_dev(0);
+ hci_read_voice_setting(dd, &vs, 1000);
+ vs = htobs(vs);
+ fprintf(stderr, "Voice setting: 0x%04x\n", vs);
+ close(dd);
+ if (vs != 0x0060) {
+ fprintf(stderr, "The voice setting must be 0x0060\n");
+ return -1;
+ }
+
+ if (strcmp(filename, "-") == 0) {
+ switch (mode) {
+ case PLAY:
+ fd = 0;
+ break;
+ case RECORD:
+ fd = 1;
+ break;
+ default:
+ return -1;
+ }
+ } else {
+ if ((fd = open(filename, filemode)) < 0) {
+ perror("Can't open input/output file");
+ return -1;
+ }
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) {
+ perror("Can't connect RFCOMM channel");
+ return -1;
+ }
+
+ fprintf(stderr, "RFCOMM channel connected\n");
+
+ if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) {
+ perror("Can't connect SCO audio channel");
+ close(rd);
+ return -1;
+ }
+
+ fprintf(stderr, "SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu);
+
+ if (mode == RECORD)
+ err = write(rd, "RING\r\n", 6);
+
+ maxfd = (rd > sd) ? rd : sd;
+
+ while (!terminate) {
+
+ FD_ZERO(&rfds);
+ FD_SET(rd, &rfds);
+ FD_SET(sd, &rfds);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+
+ if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) {
+
+ if (FD_ISSET(rd, &rfds)) {
+ memset(buf, 0, sizeof(buf));
+ rlen = read(rd, buf, sizeof(buf));
+ if (rlen > 0) {
+ fprintf(stderr, "%s\n", buf);
+ wlen = write(rd, "OK\r\n", 4);
+ }
+ }
+
+ if (FD_ISSET(sd, &rfds)) {
+ memset(buf, 0, sizeof(buf));
+ rlen = read(sd, buf, sizeof(buf));
+ if (rlen > 0)
+ switch (mode) {
+ case PLAY:
+ rlen = read(fd, buf, rlen);
+
+ wlen = 0;
+ p = buf;
+ while (rlen > sco_mtu) {
+ wlen += write(sd, p, sco_mtu);
+ rlen -= sco_mtu;
+ p += sco_mtu;
+ }
+ wlen += write(sd, p, rlen);
+ break;
+ case RECORD:
+ wlen = write(fd, buf, rlen);
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ }
+
+ close(sd);
+ sleep(5);
+ close(rd);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/utils/test/l2test.c b/utils/test/l2test.c
new file mode 100644
index 00000000..a6ff75fa
--- /dev/null
+++ b/utils/test/l2test.c
@@ -0,0 +1,1096 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+
+#define NIBBLE_TO_ASCII(c) ((c) < 0x0a ? (c) + 0x30 : (c) + 0x57)
+
+/* Test modes */
+enum {
+ SEND,
+ RECV,
+ RECONNECT,
+ MULTY,
+ DUMP,
+ CONNECT,
+ CRECV,
+ LSEND,
+ SENDDUMP,
+ LSENDDUMP,
+ INFOREQ
+};
+
+static unsigned char *buf;
+
+/* Default mtu */
+static int imtu = 672;
+static int omtu = 0;
+
+/* Default data size */
+static long data_size = -1;
+
+/* Default addr and psm */
+static bdaddr_t bdaddr;
+static unsigned short psm = 10;
+
+/* Default number of frames to send (-1 = infinite) */
+static int num_frames = -1;
+
+/* Default number of consecutive frames before the delay */
+static int count = 1;
+
+/* Default delay after sending count number of frames */
+static unsigned long delay = 0;
+
+static char *filename = NULL;
+
+static int rfcmode = 0;
+static int master = 0;
+static int auth = 0;
+static int encrypt = 0;
+static int secure = 0;
+static int socktype = SOCK_SEQPACKET;
+static int linger = 0;
+static int reliable = 0;
+static int timestamp = 0;
+
+static float tv2fl(struct timeval tv)
+{
+ return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
+}
+
+static char *ltoh(unsigned long c, char* s)
+{
+ int c1;
+
+ c1 = (c >> 28) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = (c >> 24) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = (c >> 20) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = (c >> 16) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = (c >> 12) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = (c >> 8) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = (c >> 4) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = c & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ *s = 0;
+ return s;
+}
+
+static char *ctoh(char c, char* s)
+{
+ char c1;
+
+ c1 = (c >> 4) & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ c1 = c & 0x0f;
+ *(s++) = NIBBLE_TO_ASCII (c1);
+ *s = 0;
+ return s;
+}
+
+static void hexdump(unsigned char *s, unsigned long l)
+{
+ char bfr[80];
+ char *pb;
+ unsigned long i, n = 0;
+
+ if (l == 0)
+ return;
+
+ while (n < l) {
+ pb = bfr;
+ pb = ltoh (n, pb);
+ *(pb++) = ':';
+ *(pb++) = ' ';
+ for (i = 0; i < 16; i++) {
+ if (n + i >= l) {
+ *(pb++) = ' ';
+ *(pb++) = ' ';
+ } else
+ pb = ctoh (*(s + i), pb);
+ *(pb++) = ' ';
+ }
+ *(pb++) = ' ';
+ for (i = 0; i < 16; i++) {
+ if (n + i >= l)
+ break;
+ else
+ *(pb++) = (isprint (*(s + i)) ? *(s + i) : '.');
+ }
+ *pb = 0;
+ n += 16;
+ s += 16;
+ puts(bfr);
+ }
+}
+
+static int do_connect(char *svr)
+{
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ struct l2cap_conninfo conn;
+ socklen_t optlen;
+ int sk, opt;
+
+ /* Create socket */
+ sk = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, &bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Get default options */
+ memset(&opts, 0, sizeof(opts));
+ optlen = sizeof(opts);
+
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Set new options */
+ opts.omtu = omtu;
+ opts.imtu = imtu;
+ if (rfcmode > 0)
+ opts.mode = rfcmode;
+
+ if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
+ syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+#if 0
+ /* Enable SO_TIMESTAMP */
+ if (timestamp) {
+ int t = 1;
+
+ if (setsockopt(sk, SOL_SOCKET, SO_TIMESTAMP, &t, sizeof(t)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_TIMESTAMP: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ }
+#endif
+
+ /* Enable SO_LINGER */
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ }
+
+ /* Set link mode */
+ opt = 0;
+ if (reliable)
+ opt |= L2CAP_LM_RELIABLE;
+
+ if (setsockopt(sk, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) {
+ syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Connect to remote device */
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba(svr, &addr.l2_bdaddr);
+ addr.l2_psm = htobs(psm);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) {
+ syslog(LOG_ERR, "Can't connect: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Get current options */
+ memset(&opts, 0, sizeof(opts));
+ optlen = sizeof(opts);
+
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Get connection information */
+ memset(&conn, 0, sizeof(conn));
+ optlen = sizeof(conn);
+
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ syslog(LOG_INFO, "Connected [imtu %d, omtu %d, flush_to %d, "
+ "mode %d, handle %d, class 0x%02x%02x%02x]",
+ opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle,
+ conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+
+ if (data_size > opts.omtu)
+ data_size = opts.omtu;
+
+ return sk;
+
+error:
+ close(sk);
+ return -1;
+}
+
+static void do_listen(void (*handler)(int sk))
+{
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ struct l2cap_conninfo conn;
+ socklen_t optlen;
+ int sk, nsk, opt;
+ char ba[18];
+
+ /* Create socket */
+ sk = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Bind to local address */
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, &bdaddr);
+ addr.l2_psm = htobs(psm);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Set link mode */
+ opt = 0;
+ if (reliable)
+ opt |= L2CAP_LM_RELIABLE;
+ if (master)
+ opt |= L2CAP_LM_MASTER;
+ if (auth)
+ opt |= L2CAP_LM_AUTH;
+ if (encrypt)
+ opt |= L2CAP_LM_ENCRYPT;
+ if (secure)
+ opt |= L2CAP_LM_SECURE;
+
+ if (opt && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) {
+ syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Get default options */
+ memset(&opts, 0, sizeof(opts));
+ optlen = sizeof(opts);
+
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Set new options */
+ opts.omtu = omtu;
+ opts.imtu = imtu;
+ if (rfcmode > 0)
+ opts.mode = rfcmode;
+
+ if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
+ syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ if (socktype == SOCK_DGRAM) {
+ handler(sk);
+ return;
+ }
+
+ /* Listen for connections */
+ if (listen(sk, 10)) {
+ syslog(LOG_ERR, "Can not listen on the socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Check for socket address */
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ if (getsockname(sk, (struct sockaddr *) &addr, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get socket name: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ psm = btohs(addr.l2_psm);
+
+ syslog(LOG_INFO, "Waiting for connection on psm %d ...", psm);
+
+ while(1) {
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
+ if (nsk < 0) {
+ syslog(LOG_ERR, "Accept failed: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ if (fork()) {
+ /* Parent */
+ close(nsk);
+ continue;
+ }
+ /* Child */
+ close(sk);
+
+ /* Get current options */
+ memset(&opts, 0, sizeof(opts));
+ optlen = sizeof(opts);
+
+ if (getsockopt(nsk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)",
+ strerror(errno), errno);
+ close(nsk);
+ goto error;
+ }
+
+ /* Get connection information */
+ memset(&conn, 0, sizeof(conn));
+ optlen = sizeof(conn);
+
+ if (getsockopt(nsk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)",
+ strerror(errno), errno);
+ close(nsk);
+ goto error;
+ }
+
+ ba2str(&addr.l2_bdaddr, ba);
+ syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, flush_to %d, "
+ "mode %d, handle %d, class 0x%02x%02x%02x]",
+ ba, opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle,
+ conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+
+#if 0
+ /* Enable SO_TIMESTAMP */
+ if (timestamp) {
+ int t = 1;
+
+ if (setsockopt(nsk, SOL_SOCKET, SO_TIMESTAMP, &t, sizeof(t)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_TIMESTAMP: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ }
+#endif
+
+ /* Enable SO_LINGER */
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)",
+ strerror(errno), errno);
+ close(nsk);
+ goto error;
+ }
+ }
+
+ handler(nsk);
+
+ syslog(LOG_INFO, "Disconnect: %m");
+ exit(0);
+ }
+
+ return;
+
+error:
+ close(sk);
+ exit(1);
+}
+
+static void dump_mode(int sk)
+{
+ socklen_t optlen;
+ int opt, len;
+
+ syslog(LOG_INFO, "Receiving ...");
+ while (1) {
+ fd_set rset;
+
+ FD_ZERO(&rset);
+ FD_SET(sk, &rset);
+
+ if (select(sk + 1, &rset, NULL, NULL, NULL) < 0)
+ return;
+
+ if (!FD_ISSET(sk, &rset))
+ continue;
+
+ len = read(sk, buf, data_size);
+ if (len <= 0) {
+ if (len < 0) {
+ if (reliable && (errno == ECOMM)) {
+ syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing.");
+ optlen = sizeof(opt);
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &opt, &optlen) < 0) {
+ syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)",
+ strerror(errno), errno);
+ return;
+ }
+ continue;
+ } else {
+ syslog(LOG_ERR, "Read error: %s(%d)",
+ strerror(errno), errno);
+ }
+ }
+ return;
+ }
+
+ syslog(LOG_INFO, "Recevied %d bytes", len);
+ hexdump(buf, len);
+ }
+}
+
+static void recv_mode(int sk)
+{
+ struct timeval tv_beg, tv_end, tv_diff;
+ struct pollfd p;
+ char ts[30];
+ long total;
+ uint32_t seq;
+ socklen_t optlen;
+ int opt;
+
+ syslog(LOG_INFO, "Receiving ...");
+
+ memset(ts, 0, sizeof(ts));
+
+ p.fd = sk;
+ p.events = POLLIN | POLLERR | POLLHUP;
+
+ seq = 0;
+ while (1) {
+ gettimeofday(&tv_beg, NULL);
+ total = 0;
+ while (total < data_size) {
+ uint32_t sq;
+ uint16_t l;
+ int i, len;
+
+ p.revents = 0;
+ if (poll(&p, 1, -1) <= 0)
+ return;
+
+ if (p.revents & (POLLERR | POLLHUP))
+ return;
+
+ len = recv(sk, buf, data_size, 0);
+ if (len < 0) {
+ if (reliable && (errno == ECOMM)) {
+ syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing.\n");
+ optlen = sizeof(opt);
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &opt, &optlen) < 0) {
+ syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)",
+ strerror(errno), errno);
+ return;
+ }
+ continue;
+ } else {
+ syslog(LOG_ERR, "Read failed: %s (%d)",
+ strerror(errno), errno);
+ }
+ }
+
+ if (len < 6)
+ break;
+
+ if (timestamp) {
+ struct timeval tv;
+
+ if (ioctl(sk, SIOCGSTAMP, &tv) < 0) {
+ timestamp = 0;
+ memset(ts, 0, sizeof(ts));
+ } else {
+ sprintf(ts, "[%ld.%ld] ",
+ tv.tv_sec, tv.tv_usec);
+ }
+ }
+
+ /* Check sequence */
+ sq = btohl(*(uint32_t *) buf);
+ if (seq != sq) {
+ syslog(LOG_INFO, "seq missmatch: %d -> %d", seq, sq);
+ seq = sq;
+ }
+ seq++;
+
+ /* Check length */
+ l = btohs(*(uint16_t *) (buf + 4));
+ if (len != l) {
+ syslog(LOG_INFO, "size missmatch: %d -> %d", len, l);
+ continue;
+ }
+
+ /* Verify data */
+ for (i = 6; i < len; i++) {
+ if (buf[i] != 0x7f)
+ syslog(LOG_INFO, "data missmatch: byte %d 0x%2.2x", i, buf[i]);
+ }
+
+ total += len;
+ }
+ gettimeofday(&tv_end, NULL);
+
+ timersub(&tv_end, &tv_beg, &tv_diff);
+
+ syslog(LOG_INFO,"%s%ld bytes in %.2f sec, %.2f kB/s", ts, total,
+ tv2fl(tv_diff), (float)(total / tv2fl(tv_diff) ) / 1024.0);
+ }
+}
+
+static void do_send(int sk)
+{
+ uint32_t seq;
+ int i, fd, len;
+
+ syslog(LOG_INFO, "Sending ...");
+
+ if (filename) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ syslog(LOG_ERR, "Open failed: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+ len = read(fd, buf, data_size);
+ send(sk, buf, len, 0);
+ return;
+ } else {
+ for (i = 6; i < data_size; i++)
+ buf[i] = 0x7f;
+ }
+
+ seq = 0;
+ while ((num_frames == -1) || (num_frames-- > 0)) {
+ *(uint32_t *) buf = htobl(seq);
+ *(uint16_t *) (buf + 4) = htobs(data_size);
+ seq++;
+
+ len = send(sk, buf, data_size, 0);
+ if (len < 0 || len != data_size) {
+ syslog(LOG_ERR, "Send failed: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ if (num_frames && delay && count && !(seq % count))
+ usleep(delay);
+ }
+}
+
+static void send_mode(int sk)
+{
+ do_send(sk);
+
+ syslog(LOG_INFO, "Closing channel ...");
+ if (shutdown(sk, SHUT_RDWR) < 0)
+ syslog(LOG_INFO, "Close failed: %m");
+ else
+ syslog(LOG_INFO, "Done");
+}
+
+static void senddump_mode(int sk)
+{
+ do_send(sk);
+
+ dump_mode(sk);
+}
+
+static void reconnect_mode(char *svr)
+{
+ while (1) {
+ int sk = do_connect(svr);
+ close(sk);
+ }
+}
+
+static void connect_mode(char *svr)
+{
+ struct pollfd p;
+ int sk;
+
+ if ((sk = do_connect(svr)) < 0)
+ exit(1);
+
+ p.fd = sk;
+ p.events = POLLERR | POLLHUP;
+
+ while (1) {
+ p.revents = 0;
+ if (poll(&p, 1, 500))
+ break;
+ }
+
+ syslog(LOG_INFO, "Disconnected");
+
+ close(sk);
+}
+
+static void multi_connect_mode(int argc, char *argv[])
+{
+ int i, n, sk;
+
+ while (1) {
+ for (n = 0; n < argc; n++) {
+ for (i = 0; i < count; i++) {
+ if (fork())
+ continue;
+
+ /* Child */
+ sk = do_connect(argv[n]);
+ usleep(500);
+ close(sk);
+ exit(0);
+ }
+ }
+ sleep(4);
+ }
+}
+
+static void info_request(char *svr)
+{
+ unsigned char buf[48];
+ l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
+ l2cap_info_req *req = (l2cap_info_req *) (buf + L2CAP_CMD_HDR_SIZE);
+ l2cap_info_rsp *rsp = (l2cap_info_rsp *) (buf + L2CAP_CMD_HDR_SIZE);
+ uint16_t mtu;
+ uint32_t mask;
+ struct sockaddr_l2 addr;
+ int sk, err;
+
+ sk = socket(PF_BLUETOOTH, SOCK_RAW, 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, &bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Can't bind socket");
+ goto failed;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba(svr, &addr.l2_bdaddr);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) {
+ perror("Can't connect socket");
+ goto failed;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ cmd->code = L2CAP_INFO_REQ;
+ cmd->ident = 42;
+ cmd->len = htobs(2);
+ req->type = htobs(0x0001);
+
+ if (send(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_REQ_SIZE, 0) < 0) {
+ perror("Can't send info request");
+ goto failed;
+ }
+
+ err = recv(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + 2, 0);
+ if (err < 0) {
+ perror("Can't receive info response");
+ goto failed;
+ }
+
+ switch (btohs(rsp->result)) {
+ case 0x0000:
+ mtu = btohs(bt_get_unaligned((uint16_t *) rsp->data));
+ printf("Connectionless MTU size is %d\n", mtu);
+ break;
+ case 0x0001:
+ printf("Connectionless MTU is not supported\n");
+ break;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ cmd->code = L2CAP_INFO_REQ;
+ cmd->ident = 42;
+ cmd->len = htobs(2);
+ req->type = htobs(0x0002);
+
+ if (send(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_REQ_SIZE, 0) < 0) {
+ perror("Can't send info request");
+ goto failed;
+ }
+
+ err = recv(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + 4, 0);
+ if (err < 0) {
+ perror("Can't receive info response");
+ goto failed;
+ }
+
+ switch (btohs(rsp->result)) {
+ case 0x0000:
+ mask = btohl(bt_get_unaligned((uint32_t *) rsp->data));
+ printf("Extended feature mask is 0x%04x\n", mask);
+ if (mask & 0x01)
+ printf(" Flow control mode\n");
+ if (mask & 0x02)
+ printf(" Retransmission mode\n");
+ if (mask & 0x04)
+ printf(" Bi-directional QoS\n");
+ break;
+ case 0x0001:
+ printf("Extended feature mask is not supported\n");
+ break;
+ }
+
+failed:
+ close(sk);
+}
+
+static void usage(void)
+{
+ printf("l2test - L2CAP testing\n"
+ "Usage:\n");
+ printf("\tl2test <mode> [options] [bdaddr]\n");
+ printf("Modes:\n"
+ "\t-r listen and receive\n"
+ "\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-s connect and send\n"
+ "\t-u connect and receive\n"
+ "\t-n connect and be silent\n"
+ "\t-y connect, then send, then dump incoming data\n"
+ "\t-c connect, disconnect, connect, ...\n"
+ "\t-m multiple connects\n"
+ "\t-z information request\n");
+
+ printf("Options:\n"
+ "\t[-b bytes] [-i device] [-P psm]\n"
+ "\t[-I imtu] [-O omtu]\n"
+ "\t[-L seconds] enable SO_LINGER\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[-R] reliable mode\n"
+ "\t[-G] use connectionless channel (datagram)\n"
+ "\t[-A] request authentication\n"
+ "\t[-E] request encryption\n"
+ "\t[-S] secure connection\n"
+ "\t[-M] become master\n"
+ "\t[-T] enable timestamps\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ int opt, sk, mode = RECV, need_addr = 0;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt=getopt(argc,argv,"rdscuwmnxyzb:i:P:I:O:B:N:L:C:D:X:RGAESMT")) != EOF) {
+ switch(opt) {
+ case 'r':
+ mode = RECV;
+ break;
+
+ case 's':
+ mode = SEND;
+ need_addr = 1;
+ break;
+
+ case 'w':
+ mode = LSEND;
+ break;
+
+ case 'u':
+ mode = CRECV;
+ need_addr = 1;
+ break;
+
+ case 'd':
+ mode = DUMP;
+ break;
+
+ case 'c':
+ mode = RECONNECT;
+ need_addr = 1;
+ break;
+
+ case 'n':
+ mode = CONNECT;
+ need_addr = 1;
+ break;
+
+ case 'm':
+ mode = MULTY;
+ need_addr = 1;
+ break;
+
+ case 'x':
+ mode = LSENDDUMP;
+ break;
+
+ case 'y':
+ mode = SENDDUMP;
+ break;
+
+ case 'z':
+ mode = INFOREQ;
+ need_addr = 1;
+ break;
+
+ case 'b':
+ data_size = atoi(optarg);
+ break;
+
+ case 'i':
+ if (!strncasecmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &bdaddr);
+ else
+ str2ba(optarg, &bdaddr);
+ break;
+
+ case 'P':
+ psm = atoi(optarg);
+ break;
+
+ case 'I':
+ imtu = atoi(optarg);
+ break;
+
+ case 'O':
+ omtu = atoi(optarg);
+ break;
+
+ case 'L':
+ linger = atoi(optarg);
+ break;
+
+ case 'B':
+ filename = strdup(optarg);
+ break;
+
+ case 'N':
+ num_frames = atoi(optarg);
+ break;
+
+ case 'C':
+ count = atoi(optarg);
+ break;
+
+ case 'D':
+ delay = atoi(optarg) * 1000;
+ break;
+
+ case 'X':
+ rfcmode = atoi(optarg);
+ break;
+
+ case 'R':
+ reliable = 1;
+ break;
+
+ case 'M':
+ master = 1;
+ break;
+
+ case 'A':
+ auth = 1;
+ break;
+
+ case 'E':
+ encrypt = 1;
+ break;
+
+ case 'S':
+ secure = 1;
+ break;
+
+ case 'G':
+ socktype = SOCK_DGRAM;
+ break;
+
+ case 'T':
+ timestamp = 1;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (need_addr && !(argc - optind)) {
+ usage();
+ exit(1);
+ }
+
+ if (data_size < 0) {
+ data_size = 48;
+ if (imtu > data_size)
+ data_size = imtu;
+ if (omtu > data_size)
+ data_size = omtu;
+ }
+
+ if (!(buf = malloc(data_size))) {
+ perror("Can't allocate data buffer");
+ exit(1);
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ openlog("l2test", LOG_PERROR | LOG_PID, LOG_LOCAL0);
+
+ switch (mode) {
+ case RECV:
+ do_listen(recv_mode);
+ break;
+
+ case CRECV:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+ recv_mode(sk);
+ break;
+
+ case DUMP:
+ do_listen(dump_mode);
+ break;
+
+ case SEND:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+ send_mode(sk);
+ break;
+
+ case LSEND:
+ do_listen(send_mode);
+ break;
+
+ case RECONNECT:
+ reconnect_mode(argv[optind]);
+ break;
+
+ case MULTY:
+ multi_connect_mode(argc - optind, argv + optind);
+ break;
+
+ case CONNECT:
+ connect_mode(argv[optind]);
+ break;
+
+ case SENDDUMP:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+ senddump_mode(sk);
+ break;
+
+ case LSENDDUMP:
+ do_listen(senddump_mode);
+ break;
+
+ case INFOREQ:
+ info_request(argv[optind]);
+ exit(0);
+ }
+
+ syslog(LOG_INFO, "Exit");
+
+ closelog();
+
+ return 0;
+}
diff --git a/utils/test/lmptest.c b/utils/test/lmptest.c
new file mode 100644
index 00000000..276ca071
--- /dev/null
+++ b/utils/test/lmptest.c
@@ -0,0 +1,175 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#if 0
+#define OCF_ERICSSON_SEND_LMP 0x0021
+typedef struct {
+ uint16_t handle;
+ uint8_t length;
+ uint8_t data[17];
+} __attribute__ ((packed)) ericsson_send_lmp_cp;
+#define ERICSSON_SEND_LMP_CP_SIZE 20
+
+static int ericsson_send_lmp(int dd, uint16_t handle, uint8_t length, uint8_t *data)
+{
+ struct hci_request rq;
+ ericsson_send_lmp_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = htobs(handle);
+ cp.length = length;
+ memcpy(cp.data, data, length);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = OCF_ERICSSON_SEND_LMP;
+ rq.cparam = &cp;
+ rq.clen = ERICSSON_SEND_LMP_CP_SIZE;
+ rq.rparam = NULL;
+ rq.rlen = 0;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ return 0;
+}
+#endif
+
+#define OCF_ERICSSON_WRITE_EVENTS 0x0043
+typedef struct {
+ uint8_t mask;
+ uint8_t opcode;
+ uint8_t opcode_ext;
+} __attribute__ ((packed)) ericsson_write_events_cp;
+#define ERICSSON_WRITE_EVENTS_CP_SIZE 3
+
+static int ericsson_write_events(int dd, uint8_t mask)
+{
+ struct hci_request rq;
+ ericsson_write_events_cp cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.mask = mask;
+ cp.opcode = 0x00;
+ cp.opcode_ext = 0x00;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = OCF_ERICSSON_WRITE_EVENTS;
+ rq.cparam = &cp;
+ rq.clen = ERICSSON_WRITE_EVENTS_CP_SIZE;
+ rq.rparam = NULL;
+ rq.rlen = 0;
+
+ if (hci_send_req(dd, &rq, 1000) < 0)
+ return -1;
+
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("lmptest - Utility for testing special LMP functions\n\n");
+ printf("Usage:\n"
+ "\tlmptest [-i <dev>]\n");
+}
+
+static struct option main_options[] = {
+ { "device", 1, 0, 'i' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct hci_version ver;
+ int dd, opt, dev = 0;
+
+ while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'i':
+ dev = hci_devid(optarg);
+ if (dev < 0) {
+ perror("Invalid device");
+ exit(1);
+ }
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ dd = hci_open_dev(dev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (hci_read_local_version(dd, &ver, 1000) < 0) {
+ fprintf(stderr, "Can't read version for hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ exit(1);
+ }
+
+ if (ver.manufacturer != 37 && ver.manufacturer != 48) {
+ fprintf(stderr, "Can't find supported device hci%d: %s (%d)\n",
+ dev, strerror(ENOSYS), ENOSYS);
+ hci_close_dev(dd);
+ exit(1);
+ }
+
+ if (ericsson_write_events(dd, 0x03) < 0) {
+ fprintf(stderr, "Can't activate events for hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+
+ return 0;
+}
diff --git a/utils/test/passkey-agent.c b/utils/test/passkey-agent.c
new file mode 100644
index 00000000..4a612662
--- /dev/null
+++ b/utils/test/passkey-agent.c
@@ -0,0 +1,405 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+#define INTERFACE "org.bluez.Security"
+
+static char *passkey = NULL;
+static char *address = NULL;
+
+static volatile sig_atomic_t __io_canceled = 0;
+static volatile sig_atomic_t __io_terminated = 0;
+
+static void sig_term(int sig)
+{
+ __io_canceled = 1;
+}
+
+static DBusHandlerResult agent_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *name, *old, *new;
+
+ if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!strcmp(name, "org.bluez") && *new == '\0') {
+ fprintf(stderr, "Passkey service has been terminated\n");
+ __io_terminated = 1;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult request_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *path, *address;
+ dbus_bool_t numeric;
+
+ if (!passkey)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_BOOLEAN, &numeric, DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for passkey Request method");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ fprintf(stderr, "Can't create reply message\n");
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ printf("Passkey request for device %s\n", address);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult cancel_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *path, *address;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &path, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for passkey Confirm method");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ printf("Request canceled for device %s\n", address);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ fprintf(stderr, "Can't create reply message\n");
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult release_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "Invalid arguments for passkey Release method");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!__io_canceled)
+ fprintf(stderr, "Passkey service has been released\n");
+
+ __io_terminated = 1;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ fprintf(stderr, "Can't create reply message\n");
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ dbus_connection_send(conn, reply, NULL);
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult agent_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ if (dbus_message_is_method_call(msg, "org.bluez.PasskeyAgent", "Request"))
+ return request_message(conn, msg, data);
+
+ if (dbus_message_is_method_call(msg, "org.bluez.PasskeyAgent", "Cancel"))
+ return cancel_message(conn, msg, data);
+
+ if (dbus_message_is_method_call(msg, "org.bluez.PasskeyAgent", "Release"))
+ return release_message(conn, msg, data);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static const DBusObjectPathVTable agent_table = {
+ .message_function = agent_message,
+};
+
+static int register_agent(DBusConnection *conn, const char *agent_path,
+ const char *remote_address, int use_default)
+{
+ DBusMessage *msg, *reply;
+ DBusError err;
+ const char *path, *method, *address = remote_address;
+
+ if (!dbus_connection_register_object_path(conn, agent_path,
+ &agent_table, NULL)) {
+ fprintf(stderr, "Can't register object path for agent\n");
+ return -1;
+ }
+
+ if (use_default) {
+ path = "/org/bluez";
+ method = "RegisterDefaultPasskeyAgent";
+ } else {
+ path = "/org/bluez/hci0";
+ method = "RegisterPasskeyAgent";
+ }
+
+ msg = dbus_message_new_method_call("org.bluez", path, INTERFACE, method);
+ if (!msg) {
+ fprintf(stderr, "Can't allocate new method call\n");
+ return -1;
+ }
+
+ if (use_default)
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &agent_path,
+ DBUS_TYPE_INVALID);
+ else
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &agent_path,
+ DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ fprintf(stderr, "Can't register passkey agent\n");
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "%s\n", err.message);
+ dbus_error_free(&err);
+ }
+ return -1;
+ }
+
+ dbus_message_unref(reply);
+
+ dbus_connection_flush(conn);
+
+ return 0;
+}
+
+static int unregister_agent(DBusConnection *conn, const char *agent_path,
+ const char *remote_address, int use_default)
+{
+ DBusMessage *msg, *reply;
+ DBusError err;
+ const char *path, *method, *address = remote_address;
+
+ if (use_default) {
+ path = "/org/bluez";
+ method = "UnregisterDefaultPasskeyAgent";
+ } else {
+ path = "/org/bluez/hci0";
+ method = "UnregisterPasskeyAgent";
+ }
+
+ msg = dbus_message_new_method_call("org.bluez", path, INTERFACE, method);
+ if (!msg) {
+ fprintf(stderr, "Can't allocate new method call\n");
+ dbus_connection_unref(conn);
+ exit(1);
+ }
+
+ if (use_default)
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &agent_path,
+ DBUS_TYPE_INVALID);
+ else
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &agent_path,
+ DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ fprintf(stderr, "Can't unregister passkey agent\n");
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "%s\n", err.message);
+ dbus_error_free(&err);
+ }
+ return -1;
+ }
+
+ dbus_message_unref(reply);
+
+ dbus_connection_flush(conn);
+
+ dbus_connection_unregister_object_path(conn, agent_path);
+
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Bluetooth passkey agent ver %s\n\n", VERSION);
+
+ printf("Usage:\n"
+ "\tpasskey-agent [--default] [--path agent-path] <passkey> [address]\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "default", 0, 0, 'd' },
+ { "path", 1, 0, 'p' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ DBusConnection *conn;
+ char match_string[128], default_path[128], *agent_path = NULL;
+ int opt, use_default = 0;
+
+ snprintf(default_path, sizeof(default_path),
+ "/org/bluez/passkey_agent_%d", getpid());
+
+ while ((opt = getopt_long(argc, argv, "+dp:h", main_options, NULL)) != EOF) {
+ switch(opt) {
+ case 'd':
+ use_default = 1;
+ break;
+ case 'p':
+ if (optarg[0] != '/') {
+ fprintf(stderr, "Invalid path\n");
+ exit(1);
+ }
+ agent_path = strdup(optarg);
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ passkey = strdup(argv[0]);
+ address = (argc > 1) ? strdup(argv[1]) : NULL;
+
+ if (!use_default && !address) {
+ usage();
+ exit(1);
+ }
+
+ if (!agent_path)
+ agent_path = strdup(default_path);
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ fprintf(stderr, "Can't get on system bus");
+ exit(1);
+ }
+
+ if (register_agent(conn, agent_path, address, use_default) < 0) {
+ dbus_connection_unref(conn);
+ exit(1);
+ }
+
+ if (!dbus_connection_add_filter(conn, agent_filter, NULL, NULL))
+ fprintf(stderr, "Can't add signal filter");
+
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, "org.bluez");
+
+ dbus_bus_add_match(conn, match_string, NULL);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ while (!__io_canceled && !__io_terminated) {
+ if (dbus_connection_read_write_dispatch(conn, 500) != TRUE)
+ break;
+ }
+
+ if (!__io_terminated)
+ unregister_agent(conn, agent_path, address, use_default);
+
+ if (passkey)
+ free(passkey);
+
+ dbus_connection_unref(conn);
+
+ return 0;
+}
diff --git a/utils/test/rctest.c b/utils/test/rctest.c
new file mode 100644
index 00000000..612855f3
--- /dev/null
+++ b/utils/test/rctest.c
@@ -0,0 +1,671 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/rfcomm.h>
+
+/* Test modes */
+enum {
+ SEND,
+ RECV,
+ RECONNECT,
+ MULTY,
+ DUMP,
+ CONNECT,
+ CRECV,
+ LSEND
+};
+
+static unsigned char *buf;
+
+/* Default data size */
+static long data_size = 127;
+static long num_frames = -1;
+
+/* Default number of consecutive frames before the delay */
+static int count = 1;
+
+/* Default delay after sending count number of frames */
+static unsigned long delay = 0;
+
+/* Default addr and channel */
+static bdaddr_t bdaddr;
+static uint8_t channel = 10;
+
+static char *filename = NULL;
+
+static int master = 0;
+static int auth = 0;
+static int encrypt = 0;
+static int secure = 0;
+static int socktype = SOCK_STREAM;
+static int linger = 0;
+static int timestamp = 0;
+
+static float tv2fl(struct timeval tv)
+{
+ return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
+}
+
+static int do_connect(char *svr)
+{
+ struct sockaddr_rc addr;
+ struct rfcomm_conninfo conn;
+ socklen_t optlen;
+ int sk;
+
+ /* Create socket */
+ sk = socket(PF_BLUETOOTH, socktype, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+#if 0
+ /* Enable SO_TIMESTAMP */
+ if (timestamp) {
+ int t = 1;
+
+ if (setsockopt(sk, SOL_SOCKET, SO_TIMESTAMP, &t, sizeof(t)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_TIMESTAMP: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ }
+#endif
+
+ /* Enable SO_LINGER */
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, &bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Connect to remote device */
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ str2ba(svr, &addr.rc_bdaddr);
+ addr.rc_channel = channel;
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't connect: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Get connection information */
+ memset(&conn, 0, sizeof(conn));
+ optlen = sizeof(conn);
+
+ if (getsockopt(sk, SOL_RFCOMM, RFCOMM_CONNINFO, &conn, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get RFCOMM connection information: %s (%d)",
+ strerror(errno), errno);
+ //goto error;
+ }
+
+ syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]",
+ conn.hci_handle,
+ conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+
+ return sk;
+
+error:
+ close(sk);
+ return -1;
+}
+
+static void do_listen(void (*handler)(int sk))
+{
+ struct sockaddr_rc addr;
+ struct rfcomm_conninfo conn;
+ socklen_t optlen;
+ int sk, nsk, opt;
+ char ba[18];
+
+ /* Create socket */
+ sk = socket(PF_BLUETOOTH, socktype, BTPROTO_RFCOMM);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Bind to local address */
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, &bdaddr);
+ addr.rc_channel = channel;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Set link mode */
+ opt = 0;
+ if (master)
+ opt |= RFCOMM_LM_MASTER;
+ if (auth)
+ opt |= RFCOMM_LM_AUTH;
+ if (encrypt)
+ opt |= RFCOMM_LM_ENCRYPT;
+ if (secure)
+ opt |= RFCOMM_LM_SECURE;
+
+ if (opt && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0) {
+ syslog(LOG_ERR, "Can't set RFCOMM link mode: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Listen for connections */
+ if (listen(sk, 10)) {
+ syslog(LOG_ERR,"Can not listen on the socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Check for socket address */
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ if (getsockname(sk, (struct sockaddr *) &addr, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get socket name: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ channel = addr.rc_channel;
+
+ syslog(LOG_INFO, "Waiting for connection on channel %d ...", channel);
+
+ while(1) {
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
+ if (nsk < 0) {
+ syslog(LOG_ERR,"Accept failed: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ if (fork()) {
+ /* Parent */
+ close(nsk);
+ continue;
+ }
+ /* Child */
+ close(sk);
+
+ /* Get connection information */
+ memset(&conn, 0, sizeof(conn));
+ optlen = sizeof(conn);
+
+ if (getsockopt(nsk, SOL_RFCOMM, RFCOMM_CONNINFO, &conn, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get RFCOMM connection information: %s (%d)",
+ strerror(errno), errno);
+ //close(nsk);
+ //goto error;
+ }
+
+ ba2str(&addr.rc_bdaddr, ba);
+ syslog(LOG_INFO, "Connect from %s [handle %d, class 0x%02x%02x%02x]",
+ ba, conn.hci_handle,
+ conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+
+#if 0
+ /* Enable SO_TIMESTAMP */
+ if (timestamp) {
+ int t = 1;
+
+ if (setsockopt(nsk, SOL_SOCKET, SO_TIMESTAMP, &t, sizeof(t)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_TIMESTAMP: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ }
+#endif
+
+ /* Enable SO_LINGER */
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)",
+ strerror(errno), errno);
+ close(nsk);
+ goto error;
+ }
+ }
+
+ handler(nsk);
+
+ syslog(LOG_INFO, "Disconnect: %m");
+ exit(0);
+ }
+
+ return;
+
+error:
+ close(sk);
+ exit(1);
+}
+
+static void dump_mode(int sk)
+{
+ int len;
+
+ syslog(LOG_INFO, "Receiving ...");
+ while ((len = read(sk, buf, data_size)) > 0)
+ syslog(LOG_INFO, "Recevied %d bytes", len);
+}
+
+static void recv_mode(int sk)
+{
+ struct timeval tv_beg, tv_end, tv_diff;
+ char ts[30];
+ long total;
+ uint32_t seq;
+
+ syslog(LOG_INFO, "Receiving ...");
+
+ memset(ts, 0, sizeof(ts));
+
+ seq = 0;
+ while (1) {
+ gettimeofday(&tv_beg,NULL);
+ total = 0;
+ while (total < data_size) {
+ //uint32_t sq;
+ //uint16_t l;
+ int r;
+
+ if ((r = recv(sk, buf, data_size, 0)) <= 0) {
+ if (r < 0)
+ syslog(LOG_ERR, "Read failed: %s (%d)",
+ strerror(errno), errno);
+ return;
+ }
+
+ if (timestamp) {
+ struct timeval tv;
+
+ if (ioctl(sk, SIOCGSTAMP, &tv) < 0) {
+ timestamp = 0;
+ memset(ts, 0, sizeof(ts));
+ } else {
+ sprintf(ts, "[%ld.%ld] ",
+ tv.tv_sec, tv.tv_usec);
+ }
+ }
+
+#if 0
+ /* Check sequence */
+ sq = btohl(*(uint32_t *) buf);
+ if (seq != sq) {
+ syslog(LOG_INFO, "seq missmatch: %d -> %d", seq, sq);
+ 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 */
+ for (i = 6; i < r; i++) {
+ if (buf[i] != 0x7f)
+ syslog(LOG_INFO, "data missmatch: byte %d 0x%2.2x", i, buf[i]);
+ }
+#endif
+ total += r;
+ }
+ gettimeofday(&tv_end,NULL);
+
+ timersub(&tv_end,&tv_beg,&tv_diff);
+
+ syslog(LOG_INFO,"%s%ld bytes in %.2f sec, %.2f kB/s", ts, total,
+ tv2fl(tv_diff), (float)(total / tv2fl(tv_diff) ) / 1024.0);
+ }
+}
+
+static void do_send(int sk)
+{
+ uint32_t seq;
+ int i, fd, len;
+
+ syslog(LOG_INFO,"Sending ...");
+
+ if (filename) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ syslog(LOG_ERR, "Open failed: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+ len = read(fd, buf, data_size);
+ send(sk, buf, len, 0);
+ return;
+ } else {
+ for (i = 6; i < data_size; i++)
+ buf[i] = 0x7f;
+ }
+
+ seq = 0;
+ while ((num_frames == -1) || (num_frames-- > 0)) {
+ *(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);
+ exit(1);
+ }
+
+ if (num_frames && delay && count && !(seq % count))
+ usleep(delay);
+ }
+}
+
+static void send_mode(int sk)
+{
+ do_send(sk);
+
+ syslog(LOG_INFO, "Closing channel ...");
+ if (shutdown(sk, SHUT_RDWR) < 0)
+ syslog(LOG_INFO, "Close failed: %m");
+ else
+ syslog(LOG_INFO, "Done");
+}
+
+static void reconnect_mode(char *svr)
+{
+ while(1) {
+ int sk = do_connect(svr);
+ close(sk);
+ }
+}
+
+static void multi_connect_mode(int argc, char *argv[])
+{
+ int i, n, sk;
+
+ while (1) {
+ for (n = 0; n < argc; n++) {
+ for (i = 0; i < count; i++) {
+ if (fork())
+ continue;
+
+ /* Child */
+ sk = do_connect(argv[n]);
+ usleep(500);
+ close(sk);
+ exit(0);
+ }
+ }
+ sleep(4);
+ }
+}
+
+static void usage(void)
+{
+ printf("rctest - RFCOMM testing\n"
+ "Usage:\n");
+ printf("\trctest <mode> [options] [bdaddr]\n");
+ printf("Modes:\n"
+ "\t-r listen and receive\n"
+ "\t-w listen and send\n"
+ "\t-d listen and dump incoming data\n"
+ "\t-s connect and send\n"
+ "\t-u connect and receive\n"
+ "\t-n connect and be silent\n"
+ "\t-c connect, disconnect, connect, ...\n"
+ "\t-m multiple connects\n");
+
+ printf("Options:\n"
+ "\t[-b bytes] [-i device] [-P channel]\n"
+ "\t[-L seconds] enabled SO_LINGER option\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"
+ "\t[-D milliseconds] delay after sending num frames (default = 0)\n"
+ "\t[-A] request authentication\n"
+ "\t[-E] request encryption\n"
+ "\t[-S] secure connection\n"
+ "\t[-M] become master\n"
+ "\t[-T] enable timestamps\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ int opt, sk, mode = RECV, need_addr = 0;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:B:N:MAESL:C:D:T")) != EOF) {
+ switch (opt) {
+ case 'r':
+ mode = RECV;
+ break;
+
+ case 's':
+ mode = SEND;
+ need_addr = 1;
+ break;
+
+ case 'w':
+ mode = LSEND;
+ break;
+
+ case 'u':
+ mode = CRECV;
+ need_addr = 1;
+ break;
+
+ case 'd':
+ mode = DUMP;
+ break;
+
+ case 'c':
+ mode = RECONNECT;
+ need_addr = 1;
+ break;
+
+ case 'n':
+ mode = CONNECT;
+ need_addr = 1;
+ break;
+
+ case 'm':
+ mode = MULTY;
+ need_addr = 1;
+ break;
+
+ case 'b':
+ data_size = atoi(optarg);
+ break;
+
+ case 'i':
+ if (!strncasecmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &bdaddr);
+ else
+ str2ba(optarg, &bdaddr);
+ break;
+
+ case 'P':
+ channel = atoi(optarg);
+ break;
+
+ case 'M':
+ master = 1;
+ break;
+
+ case 'A':
+ auth = 1;
+ break;
+
+ case 'E':
+ encrypt = 1;
+ break;
+
+ case 'S':
+ secure = 1;
+ break;
+
+ case 'L':
+ linger = atoi(optarg);
+ break;
+
+ case 'B':
+ filename = strdup(optarg);
+ break;
+
+ case 'N':
+ num_frames = atoi(optarg);
+ break;
+
+ case 'C':
+ count = atoi(optarg);
+ break;
+
+ case 'D':
+ delay = atoi(optarg) * 1000;
+ break;
+
+ case 'T':
+ timestamp = 1;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (need_addr && !(argc - optind)) {
+ usage();
+ exit(1);
+ }
+
+ if (!(buf = malloc(data_size))) {
+ perror("Can't allocate data buffer");
+ exit(1);
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ openlog("rctest", LOG_PERROR | LOG_PID, LOG_LOCAL0);
+
+ switch (mode) {
+ case RECV:
+ do_listen(recv_mode);
+ break;
+
+ case CRECV:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+ recv_mode(sk);
+ break;
+
+ case DUMP:
+ do_listen(dump_mode);
+ break;
+
+ case SEND:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+ send_mode(sk);
+ break;
+
+ case LSEND:
+ do_listen(send_mode);
+ break;
+
+ case RECONNECT:
+ reconnect_mode(argv[optind]);
+ break;
+
+ case MULTY:
+ multi_connect_mode(argc - optind, argv + optind);
+ break;
+
+ case CONNECT:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+ dump_mode(sk);
+ break;
+ }
+
+ syslog(LOG_INFO, "Exit");
+
+ closelog();
+
+ return 0;
+}
diff --git a/utils/test/scotest.c b/utils/test/scotest.c
new file mode 100644
index 00000000..4c5a310c
--- /dev/null
+++ b/utils/test/scotest.c
@@ -0,0 +1,434 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sco.h>
+
+/* Test modes */
+enum {
+ SEND,
+ RECV,
+ RECONNECT,
+ MULTY,
+ DUMP,
+ CONNECT
+};
+
+static unsigned char *buf;
+
+/* Default data size */
+static long data_size = 672;
+
+static bdaddr_t bdaddr;
+
+static float tv2fl(struct timeval tv)
+{
+ return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
+}
+
+static int do_connect(char *svr)
+{
+ struct sockaddr_sco addr;
+ struct sco_conninfo conn;
+ socklen_t optlen;
+ int sk;
+
+ /* Create socket */
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, &bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Connect to remote device */
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ str2ba(svr, &addr.sco_bdaddr);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't connect: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Get connection information */
+ memset(&conn, 0, sizeof(conn));
+ optlen = sizeof(conn);
+
+ if (getsockopt(sk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]",
+ conn.hci_handle,
+ conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+
+ return sk;
+
+error:
+ close(sk);
+ return -1;
+}
+
+static void do_listen(void (*handler)(int sk))
+{
+ struct sockaddr_sco addr;
+ struct sco_conninfo conn;
+ socklen_t optlen;
+ int sk, nsk;
+ char ba[18];
+
+ /* Create socket */
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Can't create socket: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, &bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ /* Listen for connections */
+ if (listen(sk, 10)) {
+ syslog(LOG_ERR,"Can not listen on the socket: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+
+ syslog(LOG_INFO,"Waiting for connection ...");
+
+ while (1) {
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
+ if (nsk < 0) {
+ syslog(LOG_ERR,"Accept failed: %s (%d)",
+ strerror(errno), errno);
+ goto error;
+ }
+ if (fork()) {
+ /* Parent */
+ close(nsk);
+ continue;
+ }
+ /* Child */
+ close(sk);
+
+ /* Get connection information */
+ memset(&conn, 0, sizeof(conn));
+ optlen = sizeof(conn);
+
+ if (getsockopt(nsk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) {
+ syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)",
+ strerror(errno), errno);
+ close(nsk);
+ goto error;
+ }
+
+ ba2str(&addr.sco_bdaddr, ba);
+ syslog(LOG_INFO, "Connect from %s [handle %d, class 0x%02x%02x%02x]",
+ ba, conn.hci_handle,
+ conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+
+ handler(nsk);
+
+ syslog(LOG_INFO, "Disconnect");
+ exit(0);
+ }
+
+ return;
+
+error:
+ close(sk);
+ exit(1);
+}
+
+static void dump_mode(int sk)
+{
+ int len;
+
+ syslog(LOG_INFO,"Receiving ...");
+ while ((len = read(sk, buf, data_size)) > 0)
+ syslog(LOG_INFO, "Recevied %d bytes", len);
+}
+
+static void recv_mode(int sk)
+{
+ struct timeval tv_beg,tv_end,tv_diff;
+ long total;
+ uint32_t seq;
+
+ syslog(LOG_INFO, "Receiving ...");
+
+ seq = 0;
+ while (1) {
+ gettimeofday(&tv_beg, NULL);
+ total = 0;
+ while (total < data_size) {
+ int r;
+ if ((r = recv(sk, buf, data_size, 0)) <= 0) {
+ if (r < 0)
+ syslog(LOG_ERR, "Read failed: %s (%d)",
+ strerror(errno), errno);
+ return;
+ }
+ total += r;
+ }
+ gettimeofday(&tv_end, NULL);
+
+ timersub(&tv_end, &tv_beg, &tv_diff);
+
+ syslog(LOG_INFO,"%ld bytes in %.2fm speed %.2f kb", total,
+ tv2fl(tv_diff) / 60.0,
+ (float)( total / tv2fl(tv_diff) ) / 1024.0 );
+ }
+}
+
+static void send_mode(char *svr)
+{
+ struct sco_options so;
+ socklen_t len;
+ uint32_t seq;
+ int i, sk;
+
+ if ((sk = do_connect(svr)) < 0) {
+ syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ len = sizeof(so);
+ if (getsockopt(sk, SOL_SCO, SCO_OPTIONS, &so, &len) < 0) {
+ syslog(LOG_ERR, "Can't get SCO options: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ syslog(LOG_INFO,"Sending ...");
+
+ for (i = 6; i < so.mtu; i++)
+ buf[i] = 0x7f;
+
+ seq = 0;
+ while (1) {
+ *(uint32_t *) buf = htobl(seq);
+ *(uint16_t *) (buf + 4) = htobs(data_size);
+ seq++;
+
+ if (send(sk, buf, so.mtu, 0) <= 0) {
+ syslog(LOG_ERR, "Send failed: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ usleep(1);
+ }
+}
+
+static void reconnect_mode(char *svr)
+{
+ while (1) {
+ int sk;
+
+ if ((sk = do_connect(svr)) < 0) {
+ syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ close(sk);
+
+ sleep(5);
+ }
+}
+
+static void multy_connect_mode(char *svr)
+{
+ while (1) {
+ int i, sk;
+
+ for (i = 0; i < 10; i++){
+ if (fork())
+ continue;
+
+ /* Child */
+ sk = do_connect(svr);
+ if (sk < 0) {
+ syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
+ strerror(errno), errno);
+ }
+ close(sk);
+ exit(0);
+ }
+
+ sleep(19);
+ }
+}
+
+static void usage(void)
+{
+ printf("scotest - SCO testing\n"
+ "Usage:\n");
+ printf("\tscotest <mode> [-b bytes] [bd_addr]\n");
+ printf("Modes:\n"
+ "\t-d dump (server)\n"
+ "\t-c reconnect (client)\n"
+ "\t-m multiple connects (client)\n"
+ "\t-r receive (server)\n"
+ "\t-s connect and send (client)\n"
+ "\t-n connect and be silent (client)\n");
+}
+
+int main(int argc ,char *argv[])
+{
+ struct sigaction sa;
+ int opt, sk, mode = RECV;
+
+ while ((opt=getopt(argc,argv,"rdscmnb:")) != EOF) {
+ switch(opt) {
+ case 'r':
+ mode = RECV;
+ break;
+
+ case 's':
+ mode = SEND;
+ break;
+
+ case 'd':
+ mode = DUMP;
+ break;
+
+ case 'c':
+ mode = RECONNECT;
+ break;
+
+ case 'm':
+ mode = MULTY;
+ break;
+
+ case 'n':
+ mode = CONNECT;
+ break;
+
+ case 'b':
+ data_size = atoi(optarg);
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (!(argc - optind) && (mode != RECV && mode != DUMP)) {
+ usage();
+ exit(1);
+ }
+
+ if (!(buf = malloc(data_size))) {
+ perror("Can't allocate data buffer");
+ exit(1);
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ openlog("scotest", LOG_PERROR | LOG_PID, LOG_LOCAL0);
+
+ switch( mode ){
+ case RECV:
+ do_listen(recv_mode);
+ break;
+
+ case DUMP:
+ do_listen(dump_mode);
+ break;
+
+ case SEND:
+ send_mode(argv[optind]);
+ break;
+
+ case RECONNECT:
+ reconnect_mode(argv[optind]);
+ break;
+
+ case MULTY:
+ multy_connect_mode(argv[optind]);
+ break;
+
+ case CONNECT:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+ dump_mode(sk);
+ break;
+ }
+
+ syslog(LOG_INFO, "Exit");
+
+ closelog();
+
+ return 0;
+}
diff --git a/utils/test/sdptest.c b/utils/test/sdptest.c
new file mode 100644
index 00000000..d2213bfa
--- /dev/null
+++ b/utils/test/sdptest.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+static volatile sig_atomic_t __io_finished = 0;
+
+static void callback(uint8_t type, uint16_t status,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ printf("%02x ", rsp[i]);
+ if ((i + 1) % 8 == 0)
+ printf(" ");
+ if ((i + 1) % 16 == 0)
+ printf("\n");
+ }
+ printf("\n");
+
+ __io_finished = 1;
+}
+
+static void cmd_search(bdaddr_t *src, bdaddr_t *dst)
+{
+ sdp_session_t *session;
+ sdp_list_t *search, *attrids;
+ uint32_t range = 0x0000ffff;
+ uuid_t uuid;
+
+ session = sdp_connect(src, dst, 0);
+ if (!session) {
+ perror("Can't connect to SDP service");
+ exit(1);
+ }
+
+ sdp_set_notify(session, callback, NULL);
+
+ sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
+
+ search = sdp_list_append(NULL, &uuid);
+
+ attrids = sdp_list_append(NULL, &range);
+
+ //sdp_service_search_attr_async(session, search,
+ // SDP_ATTR_REQ_RANGE, attrids);
+
+ sdp_service_search_async(session, search, 0xffff);
+
+ sdp_list_free(attrids, NULL);
+
+ sdp_list_free(search, NULL);
+
+ while (!__io_finished)
+ sdp_process(session);
+
+ sdp_close(session);
+}
+
+static void usage(void)
+{
+ printf("sdptest - Utility for SDP testing\n\n");
+ printf("Usage:\n"
+ "\tsdptest [-i <dev>] <bdaddr>\n");
+}
+
+static struct option main_options[] = {
+ { "device", 1, 0, 'i' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ bdaddr_t src, dst;
+ int opt;
+
+ bacpy(&src, BDADDR_ANY);
+
+ while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'i':
+ if (!strncasecmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &src);
+ else
+ str2ba(optarg, &dst);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ str2ba(argv[0], &dst);
+
+ cmd_search(&src, &dst);
+
+ return 0;
+}
diff --git a/utils/tools/Makefile.am b/utils/tools/Makefile.am
new file mode 100644
index 00000000..bc46b3d4
--- /dev/null
+++ b/utils/tools/Makefile.am
@@ -0,0 +1,103 @@
+
+if TOOLS
+tools_programs = hcitool l2ping sdptool ciptool
+tools_manfiles = hcitool.1 l2ping.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 = hcisecfilter ppporc avinfo $(usb_programs)
+
+hciattach_SOURCES = hciattach.c hciattach_st.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 hcitool.1 l2ping.1 sdptool.1 ciptool.1 \
+ bccmd.8 avctrl.8 hid2hci.8 dfutool.1 dfubabel.1 example.psr
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/tools/Makefile.in b/utils/tools/Makefile.in
new file mode 100644
index 00000000..2520d682
--- /dev/null
+++ b/utils/tools/Makefile.in
@@ -0,0 +1,791 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = hciattach$(EXEEXT) hciconfig$(EXEEXT) $(am__EXEEXT_4) \
+ $(am__EXEEXT_5)
+bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
+noinst_PROGRAMS = hcisecfilter$(EXEEXT) ppporc$(EXEEXT) \
+ avinfo$(EXEEXT) $(am__EXEEXT_3)
+@BCCMD_TRUE@@USB_TRUE@am__append_1 = csr_usb.c
+@BCCMD_TRUE@@USB_TRUE@am__append_2 = @USB_LIBS@
+subdir = tools
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+@TOOLS_TRUE@am__EXEEXT_1 = hcitool$(EXEEXT) l2ping$(EXEEXT) \
+@TOOLS_TRUE@ sdptool$(EXEEXT) ciptool$(EXEEXT)
+@DFUTOOL_TRUE@am__EXEEXT_2 = dfutool$(EXEEXT)
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \
+ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+@USB_TRUE@am__EXEEXT_3 = dfubabel$(EXEEXT) avctrl$(EXEEXT)
+@BCCMD_TRUE@am__EXEEXT_4 = bccmd$(EXEEXT)
+@HID2HCI_TRUE@am__EXEEXT_5 = hid2hci$(EXEEXT)
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) $(sbin_PROGRAMS)
+avctrl_SOURCES = avctrl.c
+avctrl_OBJECTS = avctrl.$(OBJEXT)
+avctrl_DEPENDENCIES =
+avinfo_SOURCES = avinfo.c
+avinfo_OBJECTS = avinfo.$(OBJEXT)
+avinfo_DEPENDENCIES =
+am__bccmd_SOURCES_DIST = bccmd.c csr.h csr.c csr_hci.c csr_bcsp.c \
+ csr_h4.c csr_3wire.c ubcsp.h ubcsp.c csr_usb.c
+@BCCMD_TRUE@@USB_TRUE@am__objects_1 = csr_usb.$(OBJEXT)
+@BCCMD_TRUE@am_bccmd_OBJECTS = bccmd.$(OBJEXT) csr.$(OBJEXT) \
+@BCCMD_TRUE@ csr_hci.$(OBJEXT) csr_bcsp.$(OBJEXT) \
+@BCCMD_TRUE@ csr_h4.$(OBJEXT) csr_3wire.$(OBJEXT) \
+@BCCMD_TRUE@ ubcsp.$(OBJEXT) $(am__objects_1)
+bccmd_OBJECTS = $(am_bccmd_OBJECTS)
+am__DEPENDENCIES_1 =
+@BCCMD_TRUE@bccmd_DEPENDENCIES = $(am__DEPENDENCIES_1)
+ciptool_SOURCES = ciptool.c
+ciptool_OBJECTS = ciptool.$(OBJEXT)
+ciptool_DEPENDENCIES =
+dfubabel_SOURCES = dfubabel.c
+dfubabel_OBJECTS = dfubabel.$(OBJEXT)
+dfubabel_DEPENDENCIES =
+am__dfutool_SOURCES_DIST = dfutool.c dfu.h dfu.c
+@DFUTOOL_TRUE@am_dfutool_OBJECTS = dfutool.$(OBJEXT) dfu.$(OBJEXT)
+dfutool_OBJECTS = $(am_dfutool_OBJECTS)
+dfutool_DEPENDENCIES =
+am_hciattach_OBJECTS = hciattach.$(OBJEXT) hciattach_st.$(OBJEXT)
+hciattach_OBJECTS = $(am_hciattach_OBJECTS)
+hciattach_DEPENDENCIES =
+am_hciconfig_OBJECTS = hciconfig.$(OBJEXT) csr.$(OBJEXT)
+hciconfig_OBJECTS = $(am_hciconfig_OBJECTS)
+hciconfig_DEPENDENCIES = $(top_builddir)/common/libhelper.a
+hcisecfilter_SOURCES = hcisecfilter.c
+hcisecfilter_OBJECTS = hcisecfilter.$(OBJEXT)
+hcisecfilter_LDADD = $(LDADD)
+am__hcitool_SOURCES_DIST = hcitool.c
+@TOOLS_TRUE@am_hcitool_OBJECTS = hcitool.$(OBJEXT)
+hcitool_OBJECTS = $(am_hcitool_OBJECTS)
+@TOOLS_TRUE@hcitool_DEPENDENCIES = $(top_builddir)/common/libhelper.a
+hid2hci_SOURCES = hid2hci.c
+hid2hci_OBJECTS = hid2hci.$(OBJEXT)
+hid2hci_DEPENDENCIES =
+l2ping_SOURCES = l2ping.c
+l2ping_OBJECTS = l2ping.$(OBJEXT)
+l2ping_DEPENDENCIES =
+ppporc_SOURCES = ppporc.c
+ppporc_OBJECTS = ppporc.$(OBJEXT)
+ppporc_DEPENDENCIES =
+sdptool_SOURCES = sdptool.c
+sdptool_OBJECTS = sdptool.$(OBJEXT)
+@TOOLS_TRUE@sdptool_DEPENDENCIES = $(top_builddir)/common/libhelper.a
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = avctrl.c avinfo.c $(bccmd_SOURCES) ciptool.c dfubabel.c \
+ $(dfutool_SOURCES) $(hciattach_SOURCES) $(hciconfig_SOURCES) \
+ hcisecfilter.c $(hcitool_SOURCES) hid2hci.c l2ping.c ppporc.c \
+ sdptool.c
+DIST_SOURCES = avctrl.c avinfo.c $(am__bccmd_SOURCES_DIST) ciptool.c \
+ dfubabel.c $(am__dfutool_SOURCES_DIST) $(hciattach_SOURCES) \
+ $(hciconfig_SOURCES) hcisecfilter.c \
+ $(am__hcitool_SOURCES_DIST) hid2hci.c l2ping.c ppporc.c \
+ sdptool.c
+man1dir = $(mandir)/man1
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(man_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GDBUS_CFLAGS = @GDBUS_CFLAGS@
+GDBUS_LIBS = @GDBUS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GREP = @GREP@
+GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
+GSTREAMER_LIBS = @GSTREAMER_LIBS@
+GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NETLINK_CFLAGS = @NETLINK_CFLAGS@
+NETLINK_LIBS = @NETLINK_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SBC_CFLAGS = @SBC_CFLAGS@
+SBC_LIBS = @SBC_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+SNDFILE_LIBS = @SNDFILE_LIBS@
+STRIP = @STRIP@
+USB_CFLAGS = @USB_CFLAGS@
+USB_LIBS = @USB_LIBS@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@TOOLS_FALSE@tools_programs =
+@TOOLS_TRUE@tools_programs = hcitool l2ping sdptool ciptool
+@TOOLS_FALSE@tools_manfiles =
+@TOOLS_TRUE@tools_manfiles = hcitool.1 l2ping.1 sdptool.1 ciptool.1
+@BCCMD_FALSE@bccmd_programs =
+@BCCMD_TRUE@bccmd_programs = bccmd
+@BCCMD_FALSE@bccmd_manfiles =
+@BCCMD_TRUE@bccmd_manfiles = bccmd.8
+@HID2HCI_FALSE@hid2hci_programs =
+@HID2HCI_TRUE@hid2hci_programs = hid2hci
+@HID2HCI_FALSE@hid2hci_manfiles =
+@HID2HCI_TRUE@hid2hci_manfiles = hid2hci.8
+@DFUTOOL_FALSE@dfutool_programs =
+@DFUTOOL_TRUE@dfutool_programs = dfutool
+@DFUTOOL_FALSE@dfutool_manfiles =
+@DFUTOOL_TRUE@dfutool_manfiles = dfutool.1
+@USB_FALSE@usb_programs =
+@USB_TRUE@usb_programs = dfubabel avctrl
+hciattach_SOURCES = hciattach.c hciattach_st.c
+hciattach_LDADD = @BLUEZ_LIBS@
+hciconfig_SOURCES = hciconfig.c csr.h csr.c
+hciconfig_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
+@TOOLS_TRUE@hcitool_SOURCES = hcitool.c
+@TOOLS_TRUE@hcitool_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
+@TOOLS_TRUE@l2ping_LDADD = @BLUEZ_LIBS@
+@TOOLS_TRUE@sdptool_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
+@TOOLS_TRUE@ciptool_LDADD = @BLUEZ_LIBS@
+@TOOLS_TRUE@avinfo_LDADD = @BLUEZ_LIBS@
+ppporc_LDADD = @BLUEZ_LIBS@
+@BCCMD_TRUE@bccmd_SOURCES = bccmd.c csr.h csr.c csr_hci.c csr_bcsp.c \
+@BCCMD_TRUE@ csr_h4.c csr_3wire.c ubcsp.h ubcsp.c \
+@BCCMD_TRUE@ $(am__append_1)
+@BCCMD_TRUE@bccmd_LDADD = @BLUEZ_LIBS@ $(am__append_2)
+@HID2HCI_TRUE@hid2hci_LDADD = @USB_LIBS@
+@DFUTOOL_TRUE@dfutool_SOURCES = dfutool.c dfu.h dfu.c
+@DFUTOOL_TRUE@dfutool_LDADD = @USB_LIBS@
+@USB_TRUE@dfubabel_LDADD = @USB_LIBS@
+@USB_TRUE@avctrl_LDADD = @USB_LIBS@
+AM_CFLAGS = @BLUEZ_CFLAGS@ @USB_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
+@MANPAGES_TRUE@man_MANS = hciattach.8 hciconfig.8 $(tools_manfiles) \
+@MANPAGES_TRUE@ $(bccmd_manfiles) $(hid2hci_manfiles) $(dfutool_manfiles)
+
+EXTRA_DIST = hciattach.8 hciconfig.8 hcitool.1 l2ping.1 sdptool.1 ciptool.1 \
+ bccmd.8 avctrl.8 hid2hci.8 dfutool.1 dfubabel.1 example.psr
+
+MAINTAINERCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tools/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu tools/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sbindir)/$$f"; \
+ done
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+avctrl$(EXEEXT): $(avctrl_OBJECTS) $(avctrl_DEPENDENCIES)
+ @rm -f avctrl$(EXEEXT)
+ $(LINK) $(avctrl_OBJECTS) $(avctrl_LDADD) $(LIBS)
+avinfo$(EXEEXT): $(avinfo_OBJECTS) $(avinfo_DEPENDENCIES)
+ @rm -f avinfo$(EXEEXT)
+ $(LINK) $(avinfo_OBJECTS) $(avinfo_LDADD) $(LIBS)
+bccmd$(EXEEXT): $(bccmd_OBJECTS) $(bccmd_DEPENDENCIES)
+ @rm -f bccmd$(EXEEXT)
+ $(LINK) $(bccmd_OBJECTS) $(bccmd_LDADD) $(LIBS)
+ciptool$(EXEEXT): $(ciptool_OBJECTS) $(ciptool_DEPENDENCIES)
+ @rm -f ciptool$(EXEEXT)
+ $(LINK) $(ciptool_OBJECTS) $(ciptool_LDADD) $(LIBS)
+dfubabel$(EXEEXT): $(dfubabel_OBJECTS) $(dfubabel_DEPENDENCIES)
+ @rm -f dfubabel$(EXEEXT)
+ $(LINK) $(dfubabel_OBJECTS) $(dfubabel_LDADD) $(LIBS)
+dfutool$(EXEEXT): $(dfutool_OBJECTS) $(dfutool_DEPENDENCIES)
+ @rm -f dfutool$(EXEEXT)
+ $(LINK) $(dfutool_OBJECTS) $(dfutool_LDADD) $(LIBS)
+hciattach$(EXEEXT): $(hciattach_OBJECTS) $(hciattach_DEPENDENCIES)
+ @rm -f hciattach$(EXEEXT)
+ $(LINK) $(hciattach_OBJECTS) $(hciattach_LDADD) $(LIBS)
+hciconfig$(EXEEXT): $(hciconfig_OBJECTS) $(hciconfig_DEPENDENCIES)
+ @rm -f hciconfig$(EXEEXT)
+ $(LINK) $(hciconfig_OBJECTS) $(hciconfig_LDADD) $(LIBS)
+hcisecfilter$(EXEEXT): $(hcisecfilter_OBJECTS) $(hcisecfilter_DEPENDENCIES)
+ @rm -f hcisecfilter$(EXEEXT)
+ $(LINK) $(hcisecfilter_OBJECTS) $(hcisecfilter_LDADD) $(LIBS)
+hcitool$(EXEEXT): $(hcitool_OBJECTS) $(hcitool_DEPENDENCIES)
+ @rm -f hcitool$(EXEEXT)
+ $(LINK) $(hcitool_OBJECTS) $(hcitool_LDADD) $(LIBS)
+hid2hci$(EXEEXT): $(hid2hci_OBJECTS) $(hid2hci_DEPENDENCIES)
+ @rm -f hid2hci$(EXEEXT)
+ $(LINK) $(hid2hci_OBJECTS) $(hid2hci_LDADD) $(LIBS)
+l2ping$(EXEEXT): $(l2ping_OBJECTS) $(l2ping_DEPENDENCIES)
+ @rm -f l2ping$(EXEEXT)
+ $(LINK) $(l2ping_OBJECTS) $(l2ping_LDADD) $(LIBS)
+ppporc$(EXEEXT): $(ppporc_OBJECTS) $(ppporc_DEPENDENCIES)
+ @rm -f ppporc$(EXEEXT)
+ $(LINK) $(ppporc_OBJECTS) $(ppporc_LDADD) $(LIBS)
+sdptool$(EXEEXT): $(sdptool_OBJECTS) $(sdptool_DEPENDENCIES)
+ @rm -f sdptool$(EXEEXT)
+ $(LINK) $(sdptool_OBJECTS) $(sdptool_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avctrl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bccmd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ciptool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csr_3wire.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csr_bcsp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csr_h4.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csr_hci.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csr_usb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfubabel.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfutool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hciattach.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hciattach_st.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hciconfig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hcisecfilter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hcitool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hid2hci.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/l2ping.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppporc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdptool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubcsp.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(man1_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 1*) ;; \
+ *) ext='1' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
+ done
+install-man8: $(man8_MANS) $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
+ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+ for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ case "$$ext" in \
+ 8*) ;; \
+ *) ext='8' ;; \
+ esac; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed -e 's/^.*\///'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool \
+ clean-noinstPROGRAMS clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man: install-man1 install-man8
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-man \
+ uninstall-sbinPROGRAMS
+
+uninstall-man: uninstall-man1 uninstall-man8
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool clean-noinstPROGRAMS \
+ clean-sbinPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-man8 install-pdf install-pdf-am \
+ install-ps install-ps-am install-sbinPROGRAMS install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-man uninstall-man1 uninstall-man8 \
+ uninstall-sbinPROGRAMS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/utils/tools/avctrl.8 b/utils/tools/avctrl.8
new file mode 100644
index 00000000..7c3759d6
--- /dev/null
+++ b/utils/tools/avctrl.8
@@ -0,0 +1,39 @@
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.TH AVCTRL 8 "JUNE 6, 2005" "" ""
+
+.SH NAME
+avctrl \- Bluetooth Audio/Video control utility
+.SH SYNOPSIS
+.BR "avctrl
+[
+.I options
+]
+<command>
+.SH DESCRIPTION
+.B avctrl
+is used to control the Audio/Video dongles.
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible options.
+.TP
+.BI -q
+Don't display any messages.
+.SH AUTHOR
+Written by Marcel Holtmann <marcel@holtmann.org>.
+.br
diff --git a/utils/tools/avctrl.c b/utils/tools/avctrl.c
new file mode 100644
index 00000000..61d0180d
--- /dev/null
+++ b/utils/tools/avctrl.c
@@ -0,0 +1,248 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <usb.h>
+
+#ifdef NEED_USB_GET_BUSSES
+static inline struct usb_bus *usb_get_busses(void)
+{
+ return usb_busses;
+}
+#endif
+
+#ifndef USB_DIR_OUT
+#define USB_DIR_OUT 0x00
+#endif
+
+#ifndef USB_DIR_IN
+#define USB_DIR_IN 0x80
+#endif
+
+#define HID_REQ_GET_REPORT 0x01
+#define HID_REQ_GET_IDLE 0x02
+#define HID_REQ_GET_PROTOCOL 0x03
+#define HID_REQ_SET_REPORT 0x09
+#define HID_REQ_SET_IDLE 0x0a
+#define HID_REQ_SET_PROTOCOL 0x0b
+
+struct device_info;
+
+struct device_id {
+ uint16_t vendor;
+ uint16_t product;
+ int (*func)(struct device_info *dev, int argc, char *argv[]);
+};
+
+struct device_info {
+ struct usb_device *dev;
+ struct device_id *id;
+};
+
+#define GET_STATE 0x01
+#define GET_REMOTE_BDADDR 0x02
+#define DISCOVER 0x03
+#define SWITCH_TO_DFU 0x04
+#define READ_CODEC 0x05
+
+static int dongle_csr(struct device_info *devinfo, int argc, char *argv[])
+{
+ char buf[8];
+ struct usb_dev_handle *udev;
+ int err, intf = 2;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (!strncasecmp(argv[0], "discover", 4))
+ buf[0] = DISCOVER;
+ else if (!strncasecmp(argv[0], "switch", 3))
+ buf[0] = SWITCH_TO_DFU;
+ else if (!strncasecmp(argv[0], "dfu", 3))
+ buf[0] = SWITCH_TO_DFU;
+ else
+ return -EINVAL;
+
+ udev = usb_open(devinfo->dev);
+ if (!udev)
+ return -errno;
+
+ if (usb_claim_interface(udev, intf) < 0) {
+ err = -errno;
+ usb_close(udev);
+ return err;
+ }
+
+ err = usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ HID_REQ_SET_REPORT, 0x03 << 8, intf, buf, sizeof(buf), 10000);
+
+ if (err == 0) {
+ err = -1;
+ errno = EALREADY;
+ } else {
+ if (errno == ETIMEDOUT)
+ err = 0;
+ }
+
+ usb_release_interface(udev, intf);
+ usb_close(udev);
+
+ return err;
+}
+
+static struct device_id device_list[] = {
+ { 0x0a12, 0x1004, dongle_csr },
+ { -1 }
+};
+
+static struct device_id *match_device(uint16_t vendor, uint16_t product)
+{
+ int i;
+
+ for (i = 0; device_list[i].func; i++) {
+ if (vendor == device_list[i].vendor &&
+ product == device_list[i].product)
+ return &device_list[i];
+ }
+
+ return NULL;
+}
+
+static int find_devices(struct device_info *devinfo, size_t size)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ struct device_id *id;
+ int count = 0;
+
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_get_busses(); bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next) {
+ id = match_device(dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ if (!id)
+ continue;
+
+ if (count < size) {
+ devinfo[count].dev = dev;
+ devinfo[count].id = id;
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static void usage(void)
+{
+ printf("avctrl - Bluetooth Audio/Video control utility\n\n");
+
+ printf("Usage:\n"
+ "\tavctrl [options] <command>\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-h, --help Display help\n"
+ "\t-q, --quiet Don't display any messages\n"
+ "\n");
+
+ printf("Commands:\n"
+ "\tdiscover Simulate pressing the discover button\n"
+ "\tswitch Switch the dongle to DFU mode\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "quiet", 0, 0, 'q' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct device_info dev[16];
+ int i, opt, num, quiet = 0;
+
+ while ((opt = getopt_long(argc, argv, "+qh", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'q':
+ quiet = 1;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ usb_init();
+
+ num = find_devices(dev, sizeof(dev) / sizeof(dev[0]));
+ if (num <= 0) {
+ if (!quiet)
+ fprintf(stderr, "No Audio/Video devices found\n");
+ exit(1);
+ }
+
+ for (i = 0; i < num; i++) {
+ struct device_id *id = dev[i].id;
+ int err;
+
+ if (!quiet)
+ printf("Selecting device %04x:%04x ",
+ id->vendor, id->product);
+ fflush(stdout);
+
+ err = id->func(&dev[i], argc, argv);
+ if (err < 0) {
+ if (!quiet)
+ printf("failed (%s)\n", strerror(-err));
+ } else {
+ if (!quiet)
+ printf("was successful\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/utils/tools/avinfo.c b/utils/tools/avinfo.c
new file mode 100644
index 00000000..76d29c0c
--- /dev/null
+++ b/utils/tools/avinfo.c
@@ -0,0 +1,660 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+
+#define AVDTP_PSM 25
+
+/* Commands */
+#define AVDTP_DISCOVER 0x01
+#define AVDTP_GET_CAPABILITIES 0x02
+
+#define AVDTP_PKT_TYPE_SINGLE 0x00
+
+#define AVDTP_MSG_TYPE_COMMAND 0x00
+
+/* SEP capability categories */
+#define AVDTP_MEDIA_TRANSPORT 0x01
+#define AVDTP_REPORTING 0x02
+#define AVDTP_RECOVERY 0x03
+#define AVDTP_CONTENT_PROTECTION 0x04
+#define AVDTP_HEADER_COMPRESSION 0x05
+#define AVDTP_MULTIPLEXING 0x06
+#define AVDTP_MEDIA_CODEC 0x07
+
+/* SEP types definitions */
+#define AVDTP_SEP_TYPE_SOURCE 0x00
+#define AVDTP_SEP_TYPE_SINK 0x01
+
+/* Media types definitions */
+#define AVDTP_MEDIA_TYPE_AUDIO 0x00
+#define AVDTP_MEDIA_TYPE_VIDEO 0x01
+#define AVDTP_MEDIA_TYPE_MULTIMEDIA 0x02
+
+#define A2DP_CODEC_SBC 0x00
+#define A2DP_CODEC_MPEG12 0x01
+#define A2DP_CODEC_MPEG24 0x02
+#define A2DP_CODEC_ATRAC 0x03
+
+#define SBC_SAMPLING_FREQ_16000 (1 << 3)
+#define SBC_SAMPLING_FREQ_32000 (1 << 2)
+#define SBC_SAMPLING_FREQ_44100 (1 << 1)
+#define SBC_SAMPLING_FREQ_48000 (1 << 0)
+
+#define SBC_CHANNEL_MODE_MONO (1 << 3)
+#define SBC_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define SBC_CHANNEL_MODE_STEREO (1 << 1)
+#define SBC_CHANNEL_MODE_JOINT_STEREO (1 << 0)
+
+#define SBC_BLOCK_LENGTH_4 (1 << 3)
+#define SBC_BLOCK_LENGTH_8 (1 << 2)
+#define SBC_BLOCK_LENGTH_12 (1 << 1)
+#define SBC_BLOCK_LENGTH_16 (1 << 0)
+
+#define SBC_SUBBANDS_4 (1 << 1)
+#define SBC_SUBBANDS_8 (1 << 0)
+
+#define SBC_ALLOCATION_SNR (1 << 1)
+#define SBC_ALLOCATION_LOUDNESS (1 << 0)
+
+#define MPEG_CHANNEL_MODE_MONO (1 << 3)
+#define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define MPEG_CHANNEL_MODE_STEREO (1 << 1)
+#define MPEG_CHANNEL_MODE_JOINT_STEREO (1 << 0)
+
+#define MPEG_LAYER_MP1 (1 << 2)
+#define MPEG_LAYER_MP2 (1 << 1)
+#define MPEG_LAYER_MP3 (1 << 0)
+
+#define MPEG_SAMPLING_FREQ_16000 (1 << 5)
+#define MPEG_SAMPLING_FREQ_22050 (1 << 4)
+#define MPEG_SAMPLING_FREQ_24000 (1 << 3)
+#define MPEG_SAMPLING_FREQ_32000 (1 << 2)
+#define MPEG_SAMPLING_FREQ_44100 (1 << 1)
+#define MPEG_SAMPLING_FREQ_48000 (1 << 0)
+
+#define MPEG_BIT_RATE_VBR 0x8000
+#define MPEG_BIT_RATE_320000 0x4000
+#define MPEG_BIT_RATE_256000 0x2000
+#define MPEG_BIT_RATE_224000 0x1000
+#define MPEG_BIT_RATE_192000 0x0800
+#define MPEG_BIT_RATE_160000 0x0400
+#define MPEG_BIT_RATE_128000 0x0200
+#define MPEG_BIT_RATE_112000 0x0100
+#define MPEG_BIT_RATE_96000 0x0080
+#define MPEG_BIT_RATE_80000 0x0040
+#define MPEG_BIT_RATE_64000 0x0020
+#define MPEG_BIT_RATE_56000 0x0010
+#define MPEG_BIT_RATE_48000 0x0008
+#define MPEG_BIT_RATE_40000 0x0004
+#define MPEG_BIT_RATE_32000 0x0002
+#define MPEG_BIT_RATE_FREE 0x0001
+
+struct avdtp_service_capability {
+ uint8_t category;
+ uint8_t length;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#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 seid_req {
+ struct avdtp_header header;
+ uint8_t rfa0:2;
+ uint8_t acp_seid:6;
+} __attribute__ ((packed));
+
+struct avdtp_media_codec_capability {
+ uint8_t rfa0:4;
+ uint8_t media_type:4;
+ uint8_t media_codec_type;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct sbc_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t channel_mode:4;
+ uint8_t frequency:4;
+ uint8_t allocation_method:2;
+ uint8_t subbands:2;
+ uint8_t block_length:4;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+struct mpeg_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t channel_mode:4;
+ uint8_t crc:1;
+ uint8_t layer:3;
+ uint8_t frequency:6;
+ uint8_t mpf:1;
+ uint8_t rfa:1;
+ uint16_t bitrate;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_header {
+ 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 seid_req {
+ struct avdtp_header header;
+ uint8_t acp_seid:6;
+ uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct avdtp_media_codec_capability {
+ uint8_t media_type:4;
+ uint8_t rfa0:4;
+ uint8_t media_codec_type;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+struct sbc_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t frequency:4;
+ uint8_t channel_mode:4;
+ uint8_t block_length:4;
+ uint8_t subbands:2;
+ uint8_t allocation_method:2;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+struct mpeg_codec_cap {
+ struct avdtp_media_codec_capability cap;
+ uint8_t layer:3;
+ uint8_t crc:1;
+ uint8_t channel_mode:4;
+ uint8_t rfa:1;
+ uint8_t mpf:1;
+ uint8_t frequency:6;
+ uint16_t bitrate;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct discover_resp {
+ struct avdtp_header header;
+ struct seid_info seps[0];
+} __attribute__ ((packed));
+
+struct getcap_resp {
+ struct avdtp_header header;
+ uint8_t caps[0];
+} __attribute__ ((packed));
+
+
+static void print_mpeg12(struct mpeg_codec_cap *mpeg)
+{
+ printf("\tMedia Codec: MPEG12\n\t\tChannel Modes: ");
+
+ if (mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO)
+ printf("Mono ");
+ if (mpeg->channel_mode & MPEG_CHANNEL_MODE_DUAL_CHANNEL)
+ printf("DualChannel ");
+ if (mpeg->channel_mode & MPEG_CHANNEL_MODE_STEREO)
+ printf("Stereo ");
+ if (mpeg->channel_mode & MPEG_CHANNEL_MODE_JOINT_STEREO)
+ printf("JointStereo");
+
+ printf("\n\t\tFrequencies: ");
+ if (mpeg->frequency & MPEG_SAMPLING_FREQ_16000)
+ printf("16Khz ");
+ if (mpeg->frequency & MPEG_SAMPLING_FREQ_22050)
+ printf("22.05Khz ");
+ if (mpeg->frequency & MPEG_SAMPLING_FREQ_24000)
+ printf("24Khz ");
+ if (mpeg->frequency & MPEG_SAMPLING_FREQ_32000)
+ printf("32Khz ");
+ if (mpeg->frequency & MPEG_SAMPLING_FREQ_44100)
+ printf("44.1Khz ");
+ if (mpeg->frequency & MPEG_SAMPLING_FREQ_48000)
+ printf("48Khz ");
+
+ printf("\n\t\tCRC: %s", mpeg->crc ? "Yes" : "No");
+
+ printf("\n\t\tLayer: ");
+ if (mpeg->layer & MPEG_LAYER_MP1)
+ printf("1 ");
+ if (mpeg->layer & MPEG_LAYER_MP2)
+ printf("2 ");
+ if (mpeg->layer & MPEG_LAYER_MP3)
+ printf("3 ");
+
+ printf("\n\t\tBit Rate: ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_FREE)
+ printf("Free format");
+ else {
+ if (mpeg->bitrate & MPEG_BIT_RATE_32000)
+ printf("32kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_40000)
+ printf("40kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_48000)
+ printf("48kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_56000)
+ printf("56kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_64000)
+ printf("64kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_80000)
+ printf("80kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_96000)
+ printf("96kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_112000)
+ printf("112kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_128000)
+ printf("128kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_160000)
+ printf("160kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_192000)
+ printf("192kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_224000)
+ printf("224kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_256000)
+ printf("256kbps ");
+ if (mpeg->bitrate & MPEG_BIT_RATE_320000)
+ printf("320kbps ");
+ }
+
+ printf("\n\t\tVBR: %s", mpeg->bitrate & MPEG_BIT_RATE_VBR ? "Yes" :
+ "No");
+
+ printf("\n\t\tPayload Format: ");
+ if (mpeg->mpf)
+ printf("RFC-2250 RFC-3119\n");
+ else
+ printf("RFC-2250\n");
+}
+
+static void print_sbc(struct sbc_codec_cap *sbc)
+{
+ printf("\tMedia Codec: SBC\n\t\tChannel Modes: ");
+
+ if (sbc->channel_mode & SBC_CHANNEL_MODE_MONO)
+ printf("Mono ");
+ if (sbc->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
+ printf("DualChannel ");
+ if (sbc->channel_mode & SBC_CHANNEL_MODE_STEREO)
+ printf("Stereo ");
+ if (sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
+ printf("JointStereo");
+
+ printf("\n\t\tFrequencies: ");
+ if (sbc->frequency & SBC_SAMPLING_FREQ_16000)
+ printf("16Khz ");
+ if (sbc->frequency & SBC_SAMPLING_FREQ_32000)
+ printf("32Khz ");
+ if (sbc->frequency & SBC_SAMPLING_FREQ_44100)
+ printf("44.1Khz ");
+ if (sbc->frequency & SBC_SAMPLING_FREQ_48000)
+ printf("48Khz ");
+
+ printf("\n\t\tSubbands: ");
+ if (sbc->allocation_method & SBC_SUBBANDS_4)
+ printf("4 ");
+ if (sbc->allocation_method & SBC_SUBBANDS_8)
+ printf("8");
+
+ printf("\n\t\tBlocks: ");
+ if (sbc->block_length & SBC_BLOCK_LENGTH_4)
+ printf("4 ");
+ if (sbc->block_length & SBC_BLOCK_LENGTH_8)
+ printf("8 ");
+ if (sbc->block_length & SBC_BLOCK_LENGTH_12)
+ printf("12 ");
+ if (sbc->block_length & SBC_BLOCK_LENGTH_16)
+ printf("16 ");
+
+ printf("\n\t\tBitpool Range: %d-%d\n",
+ sbc->min_bitpool, sbc->max_bitpool);
+}
+
+static void print_media_codec(struct avdtp_media_codec_capability *cap)
+{
+ switch (cap->media_codec_type) {
+ case A2DP_CODEC_SBC:
+ print_sbc((void *) cap);
+ break;
+ case A2DP_CODEC_MPEG12:
+ print_mpeg12((void *) cap);
+ break;
+ default:
+ printf("\tMedia Codec: Unknown\n");
+ }
+}
+
+static void print_caps(void *data, int size)
+{
+ int processed;
+
+ for (processed = 0; processed + 2 < size;) {
+ struct avdtp_service_capability *cap;
+
+ cap = data;
+
+ if (processed + 2 + cap->length > size) {
+ printf("Invalid capability data in getcap resp\n");
+ break;
+ }
+
+ switch (cap->category) {
+ case AVDTP_MEDIA_TRANSPORT:
+ case AVDTP_REPORTING:
+ case AVDTP_RECOVERY:
+ case AVDTP_CONTENT_PROTECTION:
+ case AVDTP_MULTIPLEXING:
+ /* FIXME: Add proper functions */
+ break;
+ case AVDTP_MEDIA_CODEC:
+ print_media_codec((void *) cap->data);
+ break;
+ }
+
+ processed += 2 + cap->length;
+ data += 2 + cap->length;
+ }
+}
+
+static void init_request(struct avdtp_header *header, int request_id)
+{
+ static int transaction = 0;
+
+ header->packet_type = AVDTP_PKT_TYPE_SINGLE;
+ header->message_type = AVDTP_MSG_TYPE_COMMAND;
+ header->transaction = transaction;
+ header->signal_id = request_id;
+
+ /* clear rfa bits */
+ header->rfa0 = 0;
+
+ transaction = (transaction + 1) % 16;
+}
+
+static int avdtp_send(int sk, void *data, int len)
+{
+ int ret;
+
+ ret = send(sk, data, len, 0);
+
+ if (ret < 0)
+ ret = -errno;
+ else if (ret != len)
+ ret = -EIO;
+
+ if (ret < 0) {
+ printf("Unable to send message: %s (%d)\n",
+ strerror(-ret), -ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int avdtp_receive(int sk, void *data, int len)
+{
+ int ret;
+
+ ret = recv(sk, data, len, 0);
+
+ if (ret < 0) {
+ printf("Unable to receive message: %s (%d)\n",
+ strerror(errno), errno);
+ return -errno;
+ }
+
+ return ret;
+}
+
+int avdtp_get_caps(int sk, int seid)
+{
+ struct seid_req req;
+ char buffer[1024];
+ struct getcap_resp *caps = (void *) buffer;
+ int ret;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req.header, AVDTP_GET_CAPABILITIES);
+ req.acp_seid = seid;
+
+ ret = avdtp_send(sk, &req, sizeof(req));
+ if (ret < 0)
+ return ret;
+
+ memset(&buffer, 0, sizeof(buffer));
+ ret = avdtp_receive(sk, caps, sizeof(buffer));
+ if (ret < 0)
+ return ret;
+
+ if (ret < (sizeof(struct getcap_resp) + 4 +
+ sizeof(struct avdtp_media_codec_capability))) {
+ printf("Invalid capabilities\n");
+ return -1;
+ }
+
+ print_caps(caps, ret);
+
+ return 0;
+}
+
+int avdtp_discover(int sk)
+{
+ struct avdtp_header req;
+ char buffer[256];
+ struct discover_resp *discover = (void *) buffer;
+ int ret, seps, i;
+
+ memset(&req, 0, sizeof(req));
+ init_request(&req, AVDTP_DISCOVER);
+
+ ret = avdtp_send(sk, &req, sizeof(req));
+ if (ret < 0)
+ return ret;
+
+ memset(&buffer, 0, sizeof(buffer));
+ ret = avdtp_receive(sk, discover, sizeof(buffer));
+ if (ret < 0)
+ return ret;
+
+ seps = (ret - sizeof(struct avdtp_header)) / sizeof(struct seid_info);
+ for (i = 0; i < seps; i++) {
+ const char *type, *media;
+
+ switch (discover->seps[i].type) {
+ case AVDTP_SEP_TYPE_SOURCE:
+ type = "Source";
+ break;
+ case AVDTP_SEP_TYPE_SINK:
+ type = "Sink";
+ break;
+ default:
+ type = "Invalid";
+ }
+
+ switch (discover->seps[i].media_type) {
+ case AVDTP_MEDIA_TYPE_AUDIO:
+ media = "Audio";
+ break;
+ case AVDTP_MEDIA_TYPE_VIDEO:
+ media = "Video";
+ break;
+ case AVDTP_MEDIA_TYPE_MULTIMEDIA:
+ media = "Multimedia";
+ break;
+ default:
+ media = "Invalid";
+ }
+
+ printf("Stream End-Point #%d: %s %s %s\n",
+ discover->seps[i].seid, media, type,
+ discover->seps[i].inuse ? "*" : "");
+
+ avdtp_get_caps(sk, discover->seps[i].seid);
+ }
+
+ return 0;
+}
+
+static int l2cap_connect(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct sockaddr_l2 l2a;
+ int sk;
+
+ memset(&l2a, 0, sizeof(l2a));
+ l2a.l2_family = AF_BLUETOOTH;
+ bacpy(&l2a.l2_bdaddr, src);
+
+ sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0) {
+ printf("Cannot create L2CAP socket. %s(%d)\n", strerror(errno),
+ errno);
+ return -errno;
+ }
+
+ if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a)) < 0) {
+ printf("Bind failed. %s (%d)\n", strerror(errno), errno);
+ return -errno;
+ }
+
+ memset(&l2a, 0, sizeof(l2a));
+ l2a.l2_family = AF_BLUETOOTH;
+ bacpy(&l2a.l2_bdaddr, dst);
+ l2a.l2_psm = htobs(AVDTP_PSM);
+
+ if (connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) < 0) {
+ printf("Connect failed. %s(%d)\n", strerror(errno), errno);
+ return -errno;
+ }
+
+ return sk;
+}
+
+static void usage()
+{
+ printf("avinfo - Audio/Video Info Tool ver %s\n", VERSION);
+ printf("Usage:\n"
+ "\tavinfo <remote address>\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ bdaddr_t src, dst;
+ int opt, sk, dev_id;
+
+ if (argc < 2) {
+ usage();
+ exit(0);
+ }
+
+ while ((opt = getopt_long(argc, argv, "h", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ bacpy(&src, BDADDR_ANY);
+ dev_id = hci_get_route(&src);
+ if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) {
+ printf("Cannot find any local adapter\n");
+ exit(-1);
+ }
+
+ printf("Connecting ... \n");
+
+ if (bachk(argv[1]) < 0) {
+ printf("Invalid argument\n");
+ exit(1);
+ }
+
+ str2ba(argv[1], &dst);
+ sk = l2cap_connect(&src, &dst);
+ if (sk < 0)
+ exit(1);
+
+ if (avdtp_discover(sk) < 0)
+ exit(1);
+
+ return 0;
+}
diff --git a/utils/tools/bccmd.8 b/utils/tools/bccmd.8
new file mode 100644
index 00000000..28cbe880
--- /dev/null
+++ b/utils/tools/bccmd.8
@@ -0,0 +1,130 @@
+.TH BCCMD 8 "Jun 20 2006" BlueZ "Linux System Administration"
+.SH NAME
+bccmd \- Utility for the CSR BCCMD interface
+.SH SYNOPSIS
+.B bccmd
+.br
+.B bccmd [-t <transport>] [-d <device>] <command> [<args>]
+.br
+.B bccmd [-h --help]
+.br
+.SH DESCRIPTION
+.B
+bccmd
+issues BlueCore commands to
+.B
+Cambridge Silicon Radio
+devices. If run without the <command> argument, a short help page will be displayed.
+.SH OPTIONS
+.TP
+.BI -t\ <transport>
+Specify the communication transport. Valid options are:
+.RS
+.TP
+.BI HCI
+Local device with Host Controller Interface (default).
+.TP
+.BI USB
+Direct USB connection.
+.TP
+.BI BCSP
+Blue Core Serial Protocol.
+.TP
+.BI H4
+H4 serial protocol.
+.TP
+.BI 3WIRE
+3WIRE protocol (not implemented).
+.SH
+.TP
+.BI -d\ <dev>
+Specify a particular device to operate on. If not specified, default is the first available HCI device
+or /dev/ttyS0 for serial transports.
+.SH COMMANDS
+.TP
+.BI builddef
+Get build definitions
+.TP
+.BI keylen\ <handle>
+Get current crypt key length
+.TP
+.BI clock
+Get local Bluetooth clock
+.TP
+.BI rand
+Get random number
+.TP
+.BI chiprev
+Get chip revision
+.TP
+.BI buildname
+Get the full build name
+.TP
+.BI panicarg
+Get panic code argument
+.TP
+.BI faultarg
+Get fault code argument
+.TP
+.BI coldreset
+Perform cold reset
+.TP
+.BI warmreset
+Perform warm reset
+.TP
+.BI disabletx
+Disable TX on the device
+.TP
+.BI enabletx
+Enable TX on the device
+.TP
+.BI singlechan\ <channel>
+Lock radio on specific channel
+.TP
+.BI hoppingon
+Revert to channel hopping
+.TP
+.BI rttxdata1\ <decimal\ freq\ MHz>\ <level>
+TXData1 radio test
+.TP
+.BI radiotest\ <decimal\ freq\ MHz>\ <level>\ <id>
+Run radio tests, tests 4, 6 and 7 are transmit tests
+.TP
+.BI memtypes
+Get memory types
+.TP
+.BI psget\ [-r]\ [-s\ <stores>]\ <key>
+Get value for PS key.
+-r sends a warm reset afterwards
+.TP
+.BI psset\ [-r]\ [-s\ <stores>]\ <key>\ <value>
+Set value for PS key.
+-r sends a warm reset afterwards
+.TP
+.BI psclr\ [-r]\ [-s\ <stores>]\ <key>
+Clear value for PS key.
+-r sends a warm reset afterwards
+.TP
+.BI pslist\ [-r]\ [-s\ <stores>]
+List all PS keys.
+-r sends a warm reset afterwards
+.TP
+.BI psread\ [-r]\ [-s\ <stores>]
+Read all PS keys.
+-r sends a warm reset afterwards
+.TP
+.BI psload\ [-r]\ [-s\ <stores>]\ <file>
+Load all PS keys from PSR file.
+-r sends a warm reset afterwards
+.TP
+.BI pscheck\ [-r]\ [-s\ <stores>]\ <file>
+Check syntax of PSR file.
+-r sends a warm reset afterwards
+.SH KEYS
+bdaddr country devclass keymin keymax features commands version
+remver hciextn mapsco baudrate hostintf anafreq anaftrim usbvid
+usbpid dfupid bootmode
+.SH AUTHORS
+Written by Marcel Holtmann <marcel@holtmann.org>,
+man page by Adam Laurie <adam@algroup.co.uk>
+.PP
diff --git a/utils/tools/bccmd.c b/utils/tools/bccmd.c
new file mode 100644
index 00000000..95cb37bb
--- /dev/null
+++ b/utils/tools/bccmd.c
@@ -0,0 +1,1218 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "csr.h"
+
+#define CSR_TRANSPORT_UNKNOWN 0
+#define CSR_TRANSPORT_HCI 1
+#define CSR_TRANSPORT_USB 2
+#define CSR_TRANSPORT_BCSP 3
+#define CSR_TRANSPORT_H4 4
+#define CSR_TRANSPORT_3WIRE 5
+
+#define CSR_STORES_PSI (0x0001)
+#define CSR_STORES_PSF (0x0002)
+#define CSR_STORES_PSROM (0x0004)
+#define CSR_STORES_PSRAM (0x0008)
+#define CSR_STORES_DEFAULT (CSR_STORES_PSI | CSR_STORES_PSF)
+
+#define CSR_TYPE_NULL 0
+#define CSR_TYPE_COMPLEX 1
+#define CSR_TYPE_UINT8 2
+#define CSR_TYPE_UINT16 3
+#define CSR_TYPE_UINT32 4
+
+#define CSR_TYPE_ARRAY CSR_TYPE_COMPLEX
+#define CSR_TYPE_BDADDR CSR_TYPE_COMPLEX
+
+static inline int transport_open(int transport, char *device)
+{
+ switch (transport) {
+ case CSR_TRANSPORT_HCI:
+ return csr_open_hci(device);
+#ifdef HAVE_LIBUSB
+ case CSR_TRANSPORT_USB:
+ return csr_open_usb(device);
+#endif
+ case CSR_TRANSPORT_BCSP:
+ return csr_open_bcsp(device);
+ case CSR_TRANSPORT_H4:
+ return csr_open_h4(device);
+ case CSR_TRANSPORT_3WIRE:
+ return csr_open_3wire(device);
+ default:
+ fprintf(stderr, "Unsupported transport\n");
+ return -1;
+ }
+}
+
+static inline int transport_read(int transport, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ switch (transport) {
+ case CSR_TRANSPORT_HCI:
+ return csr_read_hci(varid, value, length);
+#ifdef HAVE_LIBUSB
+ case CSR_TRANSPORT_USB:
+ return csr_read_usb(varid, value, length);
+#endif
+ case CSR_TRANSPORT_BCSP:
+ return csr_read_bcsp(varid, value, length);
+ case CSR_TRANSPORT_H4:
+ return csr_read_h4(varid, value, length);
+ case CSR_TRANSPORT_3WIRE:
+ return csr_read_3wire(varid, value, length);
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+}
+
+static inline int transport_write(int transport, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ switch (transport) {
+ case CSR_TRANSPORT_HCI:
+ return csr_write_hci(varid, value, length);
+#ifdef HAVE_LIBUSB
+ case CSR_TRANSPORT_USB:
+ return csr_write_usb(varid, value, length);
+#endif
+ case CSR_TRANSPORT_BCSP:
+ return csr_write_bcsp(varid, value, length);
+ case CSR_TRANSPORT_H4:
+ return csr_write_h4(varid, value, length);
+ case CSR_TRANSPORT_3WIRE:
+ return csr_write_3wire(varid, value, length);
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+}
+
+static inline void transport_close(int transport)
+{
+ switch (transport) {
+ case CSR_TRANSPORT_HCI:
+ csr_close_hci();
+ break;
+#ifdef HAVE_LIBUSB
+ case CSR_TRANSPORT_USB:
+ csr_close_usb();
+ break;
+#endif
+ case CSR_TRANSPORT_BCSP:
+ csr_close_bcsp();
+ break;
+ case CSR_TRANSPORT_H4:
+ csr_close_h4();
+ break;
+ case CSR_TRANSPORT_3WIRE:
+ csr_close_3wire();
+ break;
+ }
+}
+
+static struct {
+ uint16_t pskey;
+ int type;
+ int size;
+ char *str;
+} storage[] = {
+ { CSR_PSKEY_BDADDR, CSR_TYPE_BDADDR, 8, "bdaddr" },
+ { CSR_PSKEY_COUNTRYCODE, CSR_TYPE_UINT16, 0, "country" },
+ { CSR_PSKEY_CLASSOFDEVICE, CSR_TYPE_UINT32, 0, "devclass" },
+ { CSR_PSKEY_ENC_KEY_LMIN, CSR_TYPE_UINT16, 0, "keymin" },
+ { CSR_PSKEY_ENC_KEY_LMAX, CSR_TYPE_UINT16, 0, "keymax" },
+ { CSR_PSKEY_LOCAL_SUPPORTED_FEATURES, CSR_TYPE_ARRAY, 8, "features" },
+ { CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS, CSR_TYPE_ARRAY, 18, "commands" },
+ { CSR_PSKEY_HCI_LMP_LOCAL_VERSION, CSR_TYPE_UINT16, 0, "version" },
+ { CSR_PSKEY_LMP_REMOTE_VERSION, CSR_TYPE_UINT8, 0, "remver" },
+ { CSR_PSKEY_HOSTIO_USE_HCI_EXTN, CSR_TYPE_UINT16, 0, "hciextn" },
+ { CSR_PSKEY_HOSTIO_MAP_SCO_PCM, CSR_TYPE_UINT16, 0, "mapsco" },
+ { CSR_PSKEY_UART_BAUDRATE, CSR_TYPE_UINT16, 0, "baudrate" },
+ { CSR_PSKEY_HOST_INTERFACE, CSR_TYPE_UINT16, 0, "hostintf" },
+ { CSR_PSKEY_ANA_FREQ, CSR_TYPE_UINT16, 0, "anafreq" },
+ { CSR_PSKEY_ANA_FTRIM, CSR_TYPE_UINT16, 0, "anaftrim" },
+ { CSR_PSKEY_USB_VENDOR_ID, CSR_TYPE_UINT16, 0, "usbvid" },
+ { CSR_PSKEY_USB_PRODUCT_ID, CSR_TYPE_UINT16, 0, "usbpid" },
+ { CSR_PSKEY_USB_DFU_PRODUCT_ID, CSR_TYPE_UINT16, 0, "dfupid" },
+ { CSR_PSKEY_INITIAL_BOOTMODE, CSR_TYPE_UINT16, 0, "bootmode" },
+ { 0x0000 },
+};
+
+static char *storestostr(uint16_t stores)
+{
+ switch (stores) {
+ case 0x0000:
+ return "Default";
+ case 0x0001:
+ return "psi";
+ case 0x0002:
+ return "psf";
+ case 0x0004:
+ return "psrom";
+ case 0x0008:
+ return "psram";
+ default:
+ return "Unknown";
+ }
+}
+
+static char *memorytostr(uint16_t type)
+{
+ switch (type) {
+ case 0x0000:
+ return "Flash memory";
+ case 0x0001:
+ return "EEPROM";
+ case 0x0002:
+ return "RAM (transient)";
+ case 0x0003:
+ return "ROM (or \"read-only\" flash memory)";
+ default:
+ return "Unknown";
+ }
+}
+
+#define OPT_RANGE(min, max) \
+ if (argc < (min)) { errno = EINVAL; return -1; } \
+ if (argc > (max)) { errno = E2BIG; return -1; }
+
+static struct option help_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static int opt_help(int argc, char *argv[], int *help)
+{
+ int opt;
+
+ while ((opt=getopt_long(argc, argv, "+h", help_options, NULL)) != EOF) {
+ switch (opt) {
+ case 'h':
+ if (help)
+ *help = 1;
+ break;
+ }
+ }
+
+ return optind;
+}
+
+#define OPT_HELP(range, help) \
+ opt_help(argc, argv, (help)); \
+ argc -= optind; argv += optind; optind = 0; \
+ OPT_RANGE((range), (range))
+
+static int cmd_builddef(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t def = 0x0000, nextdef = 0x0000;
+ int err = 0;
+
+ OPT_HELP(0, NULL);
+
+ printf("Build definitions:\n");
+
+ while (1) {
+ memset(array, 0, sizeof(array));
+ array[0] = def & 0xff;
+ array[1] = def >> 8;
+
+ err = transport_read(transport, CSR_VARID_GET_NEXT_BUILDDEF, array, 8);
+ if (err < 0) {
+ errno = -err;
+ break;
+ }
+
+ nextdef = array[2] | (array[3] << 8);
+
+ if (nextdef == 0x0000)
+ break;
+
+ def = nextdef;
+
+ printf("0x%04x - %s\n", def, csr_builddeftostr(def));
+ }
+
+ return err;
+}
+
+static int cmd_keylen(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t handle, keylen;
+ int err;
+
+ OPT_HELP(1, NULL);
+
+ handle = atoi(argv[0]);
+
+ memset(array, 0, sizeof(array));
+ array[0] = handle & 0xff;
+ array[1] = handle >> 8;
+
+ err = transport_read(transport, CSR_VARID_CRYPT_KEY_LENGTH, array, 8);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ handle = array[0] | (array[1] << 8);
+ keylen = array[2] | (array[3] << 8);
+
+ printf("Crypt key length: %d bit\n", keylen * 8);
+
+ return 0;
+}
+
+static int cmd_clock(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint32_t clock;
+ int err;
+
+ OPT_HELP(0, NULL);
+
+ memset(array, 0, sizeof(array));
+
+ err = transport_read(transport, CSR_VARID_BT_CLOCK, array, 8);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ clock = array[2] | (array[3] << 8) | (array[0] << 16) | (array[1] << 24);
+
+ printf("Bluetooth clock: 0x%04x (%d)\n", clock, clock);
+
+ return 0;
+}
+
+static int cmd_rand(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t rand;
+ int err;
+
+ OPT_HELP(0, NULL);
+
+ memset(array, 0, sizeof(array));
+
+ err = transport_read(transport, CSR_VARID_RAND, array, 8);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ rand = array[0] | (array[1] << 8);
+
+ printf("Random number: 0x%02x (%d)\n", rand, rand);
+
+ return 0;
+}
+
+static int cmd_chiprev(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t rev;
+ char *str;
+ int err;
+
+ OPT_HELP(0, NULL);
+
+ memset(array, 0, sizeof(array));
+
+ err = transport_read(transport, CSR_VARID_CHIPREV, array, 8);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ rev = array[0] | (array[1] << 8);
+
+ switch (rev) {
+ case 0x64:
+ str = "BC1 ES";
+ break;
+ case 0x65:
+ str = "BC1";
+ break;
+ case 0x89:
+ str = "BC2-External A";
+ break;
+ case 0x8a:
+ str = "BC2-External B";
+ break;
+ case 0x28:
+ str = "BC2-ROM";
+ break;
+ case 0x43:
+ str = "BC3-Multimedia";
+ break;
+ case 0x15:
+ str = "BC3-ROM";
+ break;
+ case 0xe2:
+ str = "BC3-Flash";
+ break;
+ case 0x26:
+ str = "BC4-External";
+ break;
+ case 0x30:
+ str = "BC4-ROM";
+ break;
+ default:
+ str = "NA";
+ break;
+ }
+
+ printf("Chip revision: 0x%04x (%s)\n", rev, str);
+
+ return 0;
+}
+
+static int cmd_buildname(int transport, int argc, char *argv[])
+{
+ uint8_t array[130];
+ char name[64];
+ int i, err;
+
+ OPT_HELP(0, NULL);
+
+ memset(array, 0, sizeof(array));
+
+ err = transport_read(transport, CSR_VARID_READ_BUILD_NAME, array, 128);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ for (i = 0; i < sizeof(name); i++)
+ name[i] = array[(i * 2) + 4];
+
+ printf("Build name: %s\n", name);
+
+ return 0;
+}
+
+static int cmd_panicarg(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t error;
+ int err;
+
+ OPT_HELP(0, NULL);
+
+ memset(array, 0, sizeof(array));
+
+ err = transport_read(transport, CSR_VARID_PANIC_ARG, array, 8);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ error = array[0] | (array[1] << 8);
+
+ printf("Panic code: 0x%02x (%s)\n", error,
+ error < 0x100 ? "valid" : "invalid");
+
+ return 0;
+}
+
+static int cmd_faultarg(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t error;
+ int err;
+
+ OPT_HELP(0, NULL);
+
+ memset(array, 0, sizeof(array));
+
+ err = transport_read(transport, CSR_VARID_FAULT_ARG, array, 8);
+ if (err < 0) {
+ errno = -err;
+ return -1;
+ }
+
+ error = array[0] | (array[1] << 8);
+
+ printf("Fault code: 0x%02x (%s)\n", error,
+ error < 0x100 ? "valid" : "invalid");
+
+ return 0;
+}
+
+static int cmd_coldreset(int transport, int argc, char *argv[])
+{
+ return transport_write(transport, CSR_VARID_COLD_RESET, NULL, 0);
+}
+
+static int cmd_warmreset(int transport, int argc, char *argv[])
+{
+ return transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
+}
+
+static int cmd_disabletx(int transport, int argc, char *argv[])
+{
+ return transport_write(transport, CSR_VARID_DISABLE_TX, NULL, 0);
+}
+
+static int cmd_enabletx(int transport, int argc, char *argv[])
+{
+ return transport_write(transport, CSR_VARID_ENABLE_TX, NULL, 0);
+}
+
+static int cmd_singlechan(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t channel;
+
+ OPT_HELP(1, NULL);
+
+ channel = atoi(argv[0]);
+
+ if (channel > 2401 && channel < 2481)
+ channel -= 2402;
+
+ if (channel > 78) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(array, 0, sizeof(array));
+ array[0] = channel & 0xff;
+ array[1] = channel >> 8;
+
+ return transport_write(transport, CSR_VARID_SINGLE_CHAN, array, 8);
+}
+
+static int cmd_hoppingon(int transport, int argc, char *argv[])
+{
+ return transport_write(transport, CSR_VARID_HOPPING_ON, NULL, 0);
+}
+
+static int cmd_rttxdata1(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t freq, level;
+
+ OPT_HELP(2, NULL);
+
+ freq = atoi(argv[0]);
+
+ if (!strncasecmp(argv[1], "0x", 2))
+ level = strtol(argv[1], NULL, 16);
+ else
+ level = atoi(argv[1]);
+
+ memset(array, 0, sizeof(array));
+ array[0] = 0x04;
+ array[1] = 0x00;
+ array[2] = freq & 0xff;
+ array[3] = freq >> 8;
+ array[4] = level & 0xff;
+ array[5] = level >> 8;
+
+ return transport_write(transport, CSR_VARID_RADIOTEST, array, 8);
+}
+
+static int cmd_radiotest(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t freq, level, test;
+
+ OPT_HELP(3, NULL);
+
+ freq = atoi(argv[0]);
+
+ if (!strncasecmp(argv[1], "0x", 2))
+ level = strtol(argv[1], NULL, 16);
+ else
+ level = atoi(argv[1]);
+
+ test = atoi(argv[2]);
+
+ memset(array, 0, sizeof(array));
+ array[0] = test & 0xff;
+ array[1] = test >> 8;
+ array[2] = freq & 0xff;
+ array[3] = freq >> 8;
+ array[4] = level & 0xff;
+ array[5] = level >> 8;
+
+ return transport_write(transport, CSR_VARID_RADIOTEST, array, 8);
+}
+
+static int cmd_memtypes(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t type, stores[4] = { 0x0001, 0x0002, 0x0004, 0x0008 };
+ int i, err;
+
+ OPT_HELP(0, NULL);
+
+ for (i = 0; i < 4; i++) {
+ memset(array, 0, sizeof(array));
+ array[0] = stores[i] & 0xff;
+ array[1] = stores[i] >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS_MEMORY_TYPE, array, 8);
+ if (err < 0)
+ continue;
+
+ type = array[2] + (array[3] << 8);
+
+ printf("%s (0x%04x) = %s (%d)\n", storestostr(stores[i]),
+ stores[i], memorytostr(type), type);
+ }
+
+ return 0;
+}
+
+static struct option pskey_options[] = {
+ { "stores", 1, 0, 's' },
+ { "reset", 0, 0, 'r' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static int opt_pskey(int argc, char *argv[], uint16_t *stores, int *reset, int *help)
+{
+ int opt;
+
+ while ((opt=getopt_long(argc, argv, "+s:rh", pskey_options, NULL)) != EOF) {
+ switch (opt) {
+ case 's':
+ if (!stores)
+ break;
+ if (!strcasecmp(optarg, "default"))
+ *stores = 0x0000;
+ else if (!strcasecmp(optarg, "implementation"))
+ *stores = 0x0001;
+ else if (!strcasecmp(optarg, "factory"))
+ *stores = 0x0002;
+ else if (!strcasecmp(optarg, "rom"))
+ *stores = 0x0004;
+ else if (!strcasecmp(optarg, "ram"))
+ *stores = 0x0008;
+ else if (!strcasecmp(optarg, "psi"))
+ *stores = 0x0001;
+ else if (!strcasecmp(optarg, "psf"))
+ *stores = 0x0002;
+ else if (!strcasecmp(optarg, "psrom"))
+ *stores = 0x0004;
+ else if (!strcasecmp(optarg, "psram"))
+ *stores = 0x0008;
+ else if (!strncasecmp(optarg, "0x", 2))
+ *stores = strtol(optarg, NULL, 16);
+ else
+ *stores = atoi(optarg);
+ break;
+
+ case 'r':
+ if (reset)
+ *reset = 1;
+ break;
+
+ case 'h':
+ if (help)
+ *help = 1;
+ break;
+ }
+ }
+
+ return optind;
+}
+
+#define OPT_PSKEY(min, max, stores, reset, help) \
+ opt_pskey(argc, argv, (stores), (reset), (help)); \
+ argc -= optind; argv += optind; optind = 0; \
+ OPT_RANGE((min), (max))
+
+static int cmd_psget(int transport, int argc, char *argv[])
+{
+ uint8_t array[128];
+ uint16_t pskey, length, value, stores = CSR_STORES_DEFAULT;
+ uint32_t val32;
+ int i, err, reset = 0;
+
+ memset(array, 0, sizeof(array));
+
+ OPT_PSKEY(1, 1, &stores, &reset, NULL);
+
+ if (strncasecmp(argv[0], "0x", 2)) {
+ pskey = atoi(argv[0]);
+
+ for (i = 0; storage[i].pskey; i++) {
+ if (strcasecmp(storage[i].str, argv[0]))
+ continue;
+
+ pskey = storage[i].pskey;
+ break;
+ }
+ } else
+ pskey = strtol(argv[0] + 2, NULL, 16);
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = stores & 0xff;
+ array[3] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
+ if (err < 0)
+ return err;
+
+ length = array[2] + (array[3] << 8);
+ if (length + 6 > sizeof(array) / 2)
+ return -EIO;
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = length & 0xff;
+ array[3] = length >> 8;
+ array[4] = stores & 0xff;
+ array[5] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS, array, (length + 3) * 2);
+ if (err < 0)
+ return err;
+
+ switch (length) {
+ case 1:
+ value = array[6] | (array[7] << 8);
+ printf("%s: 0x%04x (%d)\n", csr_pskeytostr(pskey), value, value);
+ break;
+
+ case 2:
+ val32 = array[8] | (array[9] << 8) | (array[6] << 16) | (array[7] << 24);
+ printf("%s: 0x%08x (%d)\n", csr_pskeytostr(pskey), val32, val32);
+ break;
+
+ default:
+ printf("%s:", csr_pskeytostr(pskey));
+ for (i = 0; i < length; i++)
+ printf(" 0x%02x%02x", array[(i * 2) + 6], array[(i * 2) + 7]);
+ printf("\n");
+ break;
+ }
+
+ if (reset)
+ transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
+
+ return err;
+}
+
+static int cmd_psset(int transport, int argc, char *argv[])
+{
+ uint8_t array[128];
+ uint16_t pskey, length, value, stores = CSR_STORES_PSRAM;
+ uint32_t val32;
+ int i, err, reset = 0;
+
+ memset(array, 0, sizeof(array));
+
+ OPT_PSKEY(2, 81, &stores, &reset, NULL);
+
+ if (strncasecmp(argv[0], "0x", 2)) {
+ pskey = atoi(argv[0]);
+
+ for (i = 0; storage[i].pskey; i++) {
+ if (strcasecmp(storage[i].str, argv[0]))
+ continue;
+
+ pskey = storage[i].pskey;
+ break;
+ }
+ } else
+ pskey = strtol(argv[0] + 2, NULL, 16);
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = stores & 0xff;
+ array[3] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
+ if (err < 0)
+ return err;
+
+ length = array[2] + (array[3] << 8);
+ if (length + 6 > sizeof(array) / 2)
+ return -EIO;
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = length & 0xff;
+ array[3] = length >> 8;
+ array[4] = stores & 0xff;
+ array[5] = stores >> 8;
+
+ argc--;
+ argv++;
+
+ switch (length) {
+ case 1:
+ if (argc != 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ if (!strncasecmp(argv[0], "0x", 2))
+ value = strtol(argv[0] + 2, NULL, 16);
+ else
+ value = atoi(argv[0]);
+
+ array[6] = value & 0xff;
+ array[7] = value >> 8;
+ break;
+
+ case 2:
+ if (argc != 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ if (!strncasecmp(argv[0], "0x", 2))
+ val32 = strtol(argv[0] + 2, NULL, 16);
+ else
+ val32 = atoi(argv[0]);
+
+ array[6] = (val32 & 0xff0000) >> 16;
+ array[7] = val32 >> 24;
+ array[8] = val32 & 0xff;
+ array[9] = (val32 & 0xff00) >> 8;
+ break;
+
+ default:
+ if (argc != length * 2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (i = 0; i < length * 2; i++)
+ if (!strncasecmp(argv[0], "0x", 2))
+ array[i + 6] = strtol(argv[i] + 2, NULL, 16);
+ else
+ array[i + 6] = atoi(argv[i]);
+ break;
+ }
+
+ err = transport_write(transport, CSR_VARID_PS, array, (length + 3) * 2);
+ if (err < 0)
+ return err;
+
+ if (reset)
+ transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
+
+ return err;
+}
+
+static int cmd_psclr(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t pskey, stores = CSR_STORES_PSRAM;
+ int i, err, reset = 0;
+
+ OPT_PSKEY(1, 1, &stores, &reset, NULL);
+
+ if (strncasecmp(argv[0], "0x", 2)) {
+ pskey = atoi(argv[0]);
+
+ for (i = 0; storage[i].pskey; i++) {
+ if (strcasecmp(storage[i].str, argv[0]))
+ continue;
+
+ pskey = storage[i].pskey;
+ break;
+ }
+ } else
+ pskey = strtol(argv[0] + 2, NULL, 16);
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = stores & 0xff;
+ array[3] = stores >> 8;
+
+ err = transport_write(transport, CSR_VARID_PS_CLR_STORES, array, 8);
+ if (err < 0)
+ return err;
+
+ if (reset)
+ transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
+
+ return err;
+}
+
+static int cmd_pslist(int transport, int argc, char *argv[])
+{
+ uint8_t array[8];
+ uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT;
+ int err, reset = 0;
+
+ OPT_PSKEY(0, 0, &stores, &reset, NULL);
+
+ while (1) {
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = stores & 0xff;
+ array[3] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8);
+ if (err < 0)
+ break;
+
+ pskey = array[4] + (array[5] << 8);
+ if (pskey == 0x0000)
+ break;
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = stores & 0xff;
+ array[3] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
+ if (err < 0)
+ continue;
+
+ length = array[2] + (array[3] << 8);
+
+ printf("0x%04x - %s (%d bytes)\n", pskey,
+ csr_pskeytostr(pskey), length * 2);
+ }
+
+ if (reset)
+ transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
+
+ return 0;
+}
+
+static int cmd_psread(int transport, int argc, char *argv[])
+{
+ uint8_t array[256];
+ uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT;
+ char *str, val[7];
+ int i, err, reset = 0;
+
+ OPT_PSKEY(0, 0, &stores, &reset, NULL);
+
+ while (1) {
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = stores & 0xff;
+ array[3] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8);
+ if (err < 0)
+ break;
+
+ pskey = array[4] + (array[5] << 8);
+ if (pskey == 0x0000)
+ break;
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = stores & 0xff;
+ array[3] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
+ if (err < 0)
+ continue;
+
+ length = array[2] + (array[3] << 8);
+ if (length + 6 > sizeof(array) / 2)
+ continue;
+
+ memset(array, 0, sizeof(array));
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = length & 0xff;
+ array[3] = length >> 8;
+ array[4] = stores & 0xff;
+ array[5] = stores >> 8;
+
+ err = transport_read(transport, CSR_VARID_PS, array, (length + 3) * 2);
+ if (err < 0)
+ continue;
+
+ str = csr_pskeytoval(pskey);
+ if (!strcasecmp(str, "UNKNOWN")) {
+ sprintf(val, "0x%04x", pskey);
+ str = NULL;
+ }
+
+ 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]);
+ printf("\n");
+ }
+
+ if (reset)
+ transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
+
+ return 0;
+}
+
+static int cmd_psload(int transport, int argc, char *argv[])
+{
+ uint8_t array[256];
+ uint16_t pskey, length, size, stores = CSR_STORES_PSRAM;
+ char *str, val[7];
+ int err, reset = 0;
+
+ OPT_PSKEY(1, 1, &stores, &reset, NULL);
+
+ psr_read(argv[0]);
+
+ memset(array, 0, sizeof(array));
+ size = sizeof(array) - 6;
+
+ while (psr_get(&pskey, array + 6, &size) == 0) {
+ str = csr_pskeytoval(pskey);
+ if (!strcasecmp(str, "UNKNOWN")) {
+ sprintf(val, "0x%04x", pskey);
+ str = NULL;
+ }
+
+ printf("Loading %s%s ... ", str ? "PSKEY_" : "",
+ str ? str : val);
+ fflush(stdout);
+
+ length = size / 2;
+
+ array[0] = pskey & 0xff;
+ array[1] = pskey >> 8;
+ array[2] = length & 0xff;
+ array[3] = length >> 8;
+ array[4] = stores & 0xff;
+ array[5] = stores >> 8;
+
+ err = transport_write(transport, CSR_VARID_PS, array, size + 6);
+
+ printf("%s\n", err < 0 ? "failed" : "done");
+
+ memset(array, 0, sizeof(array));
+ size = sizeof(array) - 6;
+ }
+
+ if (reset)
+ transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
+
+ return 0;
+}
+
+static int cmd_pscheck(int transport, int argc, char *argv[])
+{
+ uint8_t array[256];
+ uint16_t pskey, size;
+ int i;
+
+ OPT_HELP(1, NULL);
+
+ psr_read(argv[0]);
+
+ while (psr_get(&pskey, array, &size) == 0) {
+ printf("0x%04x =", pskey);
+ for (i = 0; i < size; i++)
+ printf(" 0x%02x", array[i]);
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static struct {
+ char *str;
+ int (*func)(int transport, int argc, char *argv[]);
+ char *arg;
+ char *doc;
+} commands[] = {
+ { "builddef", cmd_builddef, "", "Get build definitions" },
+ { "keylen", cmd_keylen, "<handle>", "Get current crypt key length" },
+ { "clock", cmd_clock, "", "Get local Bluetooth clock" },
+ { "rand", cmd_rand, "", "Get random number" },
+ { "chiprev", cmd_chiprev, "", "Get chip revision" },
+ { "buildname", cmd_buildname, "", "Get the full build name" },
+ { "panicarg", cmd_panicarg, "", "Get panic code argument" },
+ { "faultarg", cmd_faultarg, "", "Get fault code argument" },
+ { "coldreset", cmd_coldreset, "", "Perform cold reset" },
+ { "warmreset", cmd_warmreset, "", "Perform warm reset" },
+ { "disabletx", cmd_disabletx, "", "Disable TX on the device" },
+ { "enabletx", cmd_enabletx, "", "Enable TX on the device" },
+ { "singlechan",cmd_singlechan,"<channel>", "Lock radio on specific channel" },
+ { "hoppingon", cmd_hoppingon, "", "Revert to channel hopping" },
+ { "rttxdata1", cmd_rttxdata1, "<freq> <level>", "TXData1 radio test" },
+ { "radiotest", cmd_radiotest, "<freq> <level> <id>", "Run radio tests" },
+ { "memtypes", cmd_memtypes, NULL, "Get memory types" },
+ { "psget", cmd_psget, "<key>", "Get value for PS key" },
+ { "psset", cmd_psset, "<key> <value>", "Set value for PS key" },
+ { "psclr", cmd_psclr, "<key>", "Clear value for PS key" },
+ { "pslist", cmd_pslist, NULL, "List all PS keys" },
+ { "psread", cmd_psread, NULL, "Read all PS keys" },
+ { "psload", cmd_psload, "<file>", "Load all PS keys from PSR file" },
+ { "pscheck", cmd_pscheck, "<file>", "Check PSR file" },
+ { NULL }
+};
+
+static void usage(void)
+{
+ int i, pos = 0;
+
+ printf("bccmd - Utility for the CSR BCCMD interface\n\n");
+ printf("Usage:\n"
+ "\tbccmd [options] <command>\n\n");
+
+ printf("Options:\n"
+ "\t-t <transport> Select the transport\n"
+ "\t-d <device> Select the device\n"
+ "\t-h, --help Display help\n"
+ "\n");
+
+ printf("Transports:\n"
+ "\tHCI USB BCSP H4 3WIRE\n\n");
+
+ printf("Commands:\n");
+ for (i = 0; commands[i].str; i++)
+ printf("\t%-10s %-20s\t%s\n", commands[i].str,
+ commands[i].arg ? commands[i].arg : " ",
+ commands[i].doc);
+ printf("\n");
+
+ printf("Keys:\n\t");
+ for (i = 0; storage[i].pskey; i++) {
+ printf("%s ", storage[i].str);
+ pos += strlen(storage[i].str) + 1;
+ if (pos > 60) {
+ printf("\n\t");
+ pos = 0;
+ }
+ }
+ printf("\n");
+}
+
+static struct option main_options[] = {
+ { "transport", 1, 0, 't' },
+ { "device", 1, 0, 'd' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ char *device = NULL;
+ int i, err, opt, transport = CSR_TRANSPORT_HCI;
+
+ while ((opt=getopt_long(argc, argv, "+t:d:i:h", main_options, NULL)) != EOF) {
+ switch (opt) {
+ case 't':
+ if (!strcasecmp(optarg, "hci"))
+ transport = CSR_TRANSPORT_HCI;
+ else if (!strcasecmp(optarg, "usb"))
+ transport = CSR_TRANSPORT_USB;
+ else if (!strcasecmp(optarg, "bcsp"))
+ transport = CSR_TRANSPORT_BCSP;
+ else if (!strcasecmp(optarg, "h4"))
+ transport = CSR_TRANSPORT_H4;
+ else if (!strcasecmp(optarg, "h5"))
+ transport = CSR_TRANSPORT_3WIRE;
+ else if (!strcasecmp(optarg, "3wire"))
+ transport = CSR_TRANSPORT_3WIRE;
+ else if (!strcasecmp(optarg, "twutl"))
+ transport = CSR_TRANSPORT_3WIRE;
+ else
+ transport = CSR_TRANSPORT_UNKNOWN;
+ break;
+
+ case 'd':
+ case 'i':
+ device = strdup(optarg);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ if (transport_open(transport, device) < 0)
+ exit(1);
+
+ if (device)
+ free(device);
+
+ for (i = 0; commands[i].str; i++) {
+ if (strcasecmp(commands[i].str, argv[0]))
+ continue;
+
+ err = commands[i].func(transport, argc, argv);
+
+ transport_close(transport);
+
+ if (err < 0) {
+ fprintf(stderr, "Can't execute command: %s (%d)\n",
+ strerror(errno), errno);
+ exit(1);
+ }
+
+ exit(0);
+ }
+
+ fprintf(stderr, "Unsupported command\n");
+
+ transport_close(transport);
+
+ exit(1);
+}
diff --git a/utils/tools/ciptool.1 b/utils/tools/ciptool.1
new file mode 100644
index 00000000..982f414b
--- /dev/null
+++ b/utils/tools/ciptool.1
@@ -0,0 +1,68 @@
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.TH CIPTOOL 1 "JUNE 6, 2003" "" ""
+
+.SH NAME
+ciptool \- Bluetooth Common ISDN Access Profile (CIP)
+.SH SYNOPSIS
+.BR "ciptool
+[
+.I options
+] <
+.I command
+>
+.SH DESCRIPTION
+.B ciptool
+is used to set up, maintain, and inspect the CIP configuration
+of the Bluetooth subsystem in the Linux kernel.
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible commands.
+.TP
+.BI -i " <hciX> | <bdaddr>"
+The command is applied to device
+.I
+hciX
+, which must be the name or the address of an installed Bluetooth
+device. If not specified, the command will be use the first
+available Bluetooth device.
+.SH COMMANDS
+.TP
+.BI show
+Display information about the connected devices.
+.TP
+.BI search
+Search for Bluetooth devices and connect to first one that
+offers CIP support.
+.TP
+.BI connect " <bdaddr> [psm]"
+Connect the local device to the remote Bluetooth device on the
+specified PSM number. If no PSM is specified, it will use the
+SDP to retrieve it from the remote device.
+.TP
+.BI release " [bdaddr]"
+Release a connection to the specific device. If no address is
+given and only one device is connected this will be released.
+.TP
+.BI loopback " <bdaddr> [psm]"
+Create a connection to the remote device for Bluetooth testing.
+This command will not provide a CAPI controller, because it is
+only for testing the CAPI Message Transport Protocol.
+.SH AUTHOR
+Written by Marcel Holtmann <marcel@holtmann.org>.
+.br
diff --git a/utils/tools/ciptool.c b/utils/tools/ciptool.c
new file mode 100644
index 00000000..886e20aa
--- /dev/null
+++ b/utils/tools/ciptool.c
@@ -0,0 +1,498 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/cmtp.h>
+
+#ifdef NEED_PPOLL
+#include "ppoll.h"
+#endif
+
+static volatile sig_atomic_t __io_canceled = 0;
+
+static void sig_hup(int sig)
+{
+ return;
+}
+
+static void sig_term(int sig)
+{
+ __io_canceled = 1;
+}
+
+static char *cmtp_state[] = {
+ "unknown",
+ "connected",
+ "open",
+ "bound",
+ "listening",
+ "connecting",
+ "connecting",
+ "config",
+ "disconnecting",
+ "closed"
+};
+
+static char *cmtp_flagstostr(uint32_t flags)
+{
+ static char str[100] = "";
+
+ strcat(str, "[");
+
+ if (flags & (1 << CMTP_LOOPBACK))
+ strcat(str, "loopback");
+
+ strcat(str, "]");
+
+ return str;
+}
+
+static int get_psm(bdaddr_t *src, bdaddr_t *dst, unsigned short *psm)
+{
+ sdp_session_t *s;
+ sdp_list_t *srch, *attrs, *rsp;
+ uuid_t svclass;
+ uint16_t attr;
+ int err;
+
+ if (!(s = sdp_connect(src, dst, 0)))
+ return -1;
+
+ sdp_uuid16_create(&svclass, CIP_SVCLASS_ID);
+ srch = sdp_list_append(NULL, &svclass);
+
+ attr = SDP_ATTR_PROTO_DESC_LIST;
+ attrs = sdp_list_append(NULL, &attr);
+
+ err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+
+ sdp_close(s);
+
+ if (err)
+ return 0;
+
+ for (; rsp; rsp = rsp->next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
+ sdp_list_t *protos;
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ unsigned short p = sdp_get_proto_port(protos, L2CAP_UUID);
+ if (p > 0) {
+ *psm = p;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int do_connect(int ctl, int dev_id, bdaddr_t *src, bdaddr_t *dst, unsigned short psm, uint32_t flags)
+{
+ struct cmtp_connadd_req req;
+ struct hci_dev_info di;
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ socklen_t size;
+ int sk;
+
+ hci_devinfo(dev_id, &di);
+ if (!(di.link_policy & HCI_LP_RSWITCH)) {
+ printf("Local device is not accepting role switch\n");
+ }
+
+ if ((sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
+ perror("Can't create L2CAP socket");
+ exit(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 L2CAP socket");
+ close(sk);
+ exit(1);
+ }
+
+ memset(&opts, 0, sizeof(opts));
+ size = sizeof(opts);
+
+ if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
+ perror("Can't get L2CAP options");
+ close(sk);
+ exit(1);
+ }
+
+ opts.imtu = CMTP_DEFAULT_MTU;
+ opts.omtu = CMTP_DEFAULT_MTU;
+ opts.flush_to = 0xffff;
+
+ if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
+ perror("Can't set L2CAP options");
+ close(sk);
+ exit(1);
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(psm);
+
+ if (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror("Can't connect L2CAP socket");
+ close(sk);
+ exit(1);
+ }
+
+ req.sock = sk;
+ req.flags = flags;
+
+ if (ioctl(ctl, CMTPCONNADD, &req) < 0) {
+ perror("Can't create connection");
+ exit(1);
+ }
+
+ return sk;
+}
+
+static void cmd_show(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ struct cmtp_connlist_req req;
+ struct cmtp_conninfo ci[16];
+ char addr[18];
+ int i;
+
+ req.cnum = 16;
+ req.ci = ci;
+
+ if (ioctl(ctl, CMTPGETCONNLIST, &req) < 0) {
+ perror("Can't get connection list");
+ exit(1);
+ }
+
+ for (i = 0; i < req.cnum; i++) {
+ ba2str(&ci[i].bdaddr, addr);
+ printf("%d %s %s %s\n", ci[i].num, addr,
+ cmtp_state[ci[i].state],
+ ci[i].flags ? cmtp_flagstostr(ci[i].flags) : "");
+ }
+}
+
+static void cmd_search(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ inquiry_info *info = NULL;
+ bdaddr_t src, dst;
+ unsigned short psm;
+ int i, dev_id, num_rsp, length, flags;
+ char addr[18];
+ uint8_t class[3];
+
+ ba2str(bdaddr, addr);
+ dev_id = hci_devid(addr);
+ if (dev_id < 0) {
+ dev_id = hci_get_route(NULL);
+ hci_devba(dev_id, &src);
+ } else
+ bacpy(&src, bdaddr);
+
+ length = 8; /* ~10 seconds */
+ num_rsp = 0;
+ flags = 0;
+
+ printf("Searching ...\n");
+
+ num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags);
+
+ for (i = 0; i < num_rsp; i++) {
+ memcpy(class, (info+i)->dev_class, 3);
+ if ((class[1] == 2) && ((class[0] / 4) == 5)) {
+ bacpy(&dst, &(info+i)->bdaddr);
+ ba2str(&dst, addr);
+
+ printf("\tChecking service for %s\n", addr);
+ if (!get_psm(&src, &dst, &psm))
+ continue;
+
+ bt_free(info);
+
+ printf("\tConnecting to device %s\n", addr);
+ do_connect(ctl, dev_id, &src, &dst, psm, 0);
+ return;
+ }
+ }
+
+ bt_free(info);
+ fprintf(stderr, "\tNo devices in range or visible\n");
+ exit(1);
+}
+
+static void cmd_create(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ bdaddr_t src, dst;
+ unsigned short psm;
+ int dev_id;
+ char addr[18];
+
+ if (argc < 2)
+ return;
+
+ str2ba(argv[1], &dst);
+
+ ba2str(bdaddr, addr);
+ dev_id = hci_devid(addr);
+ if (dev_id < 0) {
+ dev_id = hci_get_route(&dst);
+ hci_devba(dev_id, &src);
+ } else
+ bacpy(&src, bdaddr);
+
+ if (argc < 3) {
+ if (!get_psm(&src, &dst, &psm))
+ psm = 4099;
+ } else
+ psm = atoi(argv[2]);
+
+ do_connect(ctl, dev_id, &src, &dst, psm, 0);
+}
+
+static void cmd_release(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ struct cmtp_conndel_req req;
+ struct cmtp_connlist_req cl;
+ struct cmtp_conninfo ci[16];
+
+ if (argc < 2) {
+ cl.cnum = 16;
+ cl.ci = ci;
+
+ if (ioctl(ctl, CMTPGETCONNLIST, &cl) < 0) {
+ perror("Can't get connection list");
+ exit(1);
+ }
+
+ if (cl.cnum == 0)
+ return;
+
+ if (cl.cnum != 1) {
+ fprintf(stderr, "You have to specifiy the device address.\n");
+ exit(1);
+ }
+
+ bacpy(&req.bdaddr, &ci[0].bdaddr);
+ } else
+ str2ba(argv[1], &req.bdaddr);
+
+ if (ioctl(ctl, CMTPCONNDEL, &req) < 0) {
+ perror("Can't release connection");
+ exit(1);
+ }
+}
+
+static void cmd_loopback(int ctl, bdaddr_t *bdaddr, int argc, char **argv)
+{
+ struct cmtp_conndel_req req;
+ struct sigaction sa;
+ struct pollfd p;
+ sigset_t sigs;
+ bdaddr_t src, dst;
+ unsigned short psm;
+ int dev_id, sk;
+ char addr[18];
+
+ if (argc < 2)
+ return;
+
+ str2ba(argv[1], &dst);
+
+ ba2str(bdaddr, addr);
+ dev_id = hci_devid(addr);
+ if (dev_id < 0) {
+ dev_id = hci_get_route(&dst);
+ hci_devba(dev_id, &src);
+ } else
+ bacpy(&src, bdaddr);
+
+ ba2str(&dst, addr);
+ printf("Connecting to %s in loopback mode\n", addr);
+
+ if (argc < 3) {
+ if (!get_psm(&src, &dst, &psm))
+ psm = 4099;
+ } else
+ psm = atoi(argv[2]);
+
+ sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK));
+
+ printf("Press CTRL-C for hangup\n");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGCHLD);
+ sigdelset(&sigs, SIGPIPE);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ p.fd = sk;
+ p.events = POLLERR | POLLHUP;
+
+ while (!__io_canceled) {
+ p.revents = 0;
+ if (ppoll(&p, 1, NULL, &sigs) > 0)
+ break;
+ }
+
+ bacpy(&req.bdaddr, &dst);
+ ioctl(ctl, CMTPCONNDEL, &req);
+}
+
+static struct {
+ char *cmd;
+ char *alt;
+ void (*func)(int ctl, bdaddr_t *bdaddr, int argc, char **argv);
+ char *opt;
+ char *doc;
+} command[] = {
+ { "show", "list", cmd_show, 0, "Show remote connections" },
+ { "search", "scan", cmd_search, 0, "Search for a remote device" },
+ { "connect", "create", cmd_create, "<bdaddr>", "Connect a remote device" },
+ { "release", "disconnect", cmd_release, "[bdaddr]", "Disconnect the remote device" },
+ { "loopback", "test", cmd_loopback, "<bdaddr>", "Loopback test of a device" },
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static void usage(void)
+{
+ int i;
+
+ printf("ciptool - Bluetooth Common ISDN Access Profile (CIP)\n\n");
+
+ printf("Usage:\n"
+ "\tciptool [options] [command]\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-i [hciX|bdaddr] Local HCI device or BD Address\n"
+ "\t-h, --help Display help\n"
+ "\n");
+
+ printf("Commands:\n");
+ for (i = 0; command[i].cmd; i++)
+ printf("\t%-8s %-10s\t%s\n", command[i].cmd,
+ command[i].opt ? command[i].opt : " ",
+ command[i].doc);
+ printf("\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device", 1, 0, 'i' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ bdaddr_t bdaddr;
+ int i, opt, ctl;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt = getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'i':
+ if (!strncmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &bdaddr);
+ else
+ str2ba(optarg, &bdaddr);
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ return 0;
+ }
+
+ if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_CMTP)) < 0 ) {
+ perror("Can't open CMTP control socket");
+ exit(1);
+ }
+
+ for (i = 0; command[i].cmd; i++) {
+ if (strncmp(command[i].cmd, argv[0], 4) && strncmp(command[i].alt, argv[0], 4))
+ continue;
+ command[i].func(ctl, &bdaddr, argc, argv);
+ close(ctl);
+ exit(0);
+ }
+
+ usage();
+
+ close(ctl);
+
+ return 0;
+}
diff --git a/utils/tools/csr.c b/utils/tools/csr.c
new file mode 100644
index 00000000..b32e4162
--- /dev/null
+++ b/utils/tools/csr.c
@@ -0,0 +1,2852 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "csr.h"
+
+struct psr_data {
+ uint16_t pskey;
+ uint8_t *value;
+ uint8_t size;
+ struct psr_data *next;
+};
+
+static struct psr_data *head = NULL, *tail = NULL;
+
+static struct {
+ uint16_t id;
+ char *str;
+} csr_map[] = {
+ { 66, "HCI 9.8" },
+ { 97, "HCI 10.3" },
+ { 101, "HCI 10.5" },
+ { 111, "HCI 11.0" },
+ { 112, "HCI 11.1" },
+ { 114, "HCI 11.2" },
+ { 115, "HCI 11.3" },
+ { 117, "HCI 12.0" },
+ { 119, "HCI 12.1" },
+ { 133, "HCI 12.2" },
+ { 134, "HCI 12.3" },
+ { 162, "HCI 12.4" },
+ { 165, "HCI 12.5" },
+ { 169, "HCI 12.6" },
+ { 188, "HCI 12.7" },
+ { 218, "HCI 12.8" },
+ { 283, "HCI 12.9" },
+ { 203, "HCI 13.2" },
+ { 204, "HCI 13.2" },
+ { 210, "HCI 13.3" },
+ { 211, "HCI 13.3" },
+ { 213, "HCI 13.4" },
+ { 214, "HCI 13.4" },
+ { 225, "HCI 13.5" },
+ { 226, "HCI 13.5" },
+ { 237, "HCI 13.6" },
+ { 238, "HCI 13.6" },
+ { 242, "HCI 14.0" },
+ { 243, "HCI 14.0" },
+ { 244, "HCI 14.0" },
+ { 245, "HCI 14.0" },
+ { 254, "HCI 13.7" },
+ { 255, "HCI 13.7" },
+ { 264, "HCI 14.1" },
+ { 265, "HCI 14.1" },
+ { 267, "HCI 14.2" },
+ { 268, "HCI 14.2" },
+ { 272, "HCI 14.3" },
+ { 273, "HCI 14.3" },
+ { 274, "HCI 13.8" },
+ { 275, "HCI 13.8" },
+ { 286, "HCI 13.9" },
+ { 287, "HCI 13.9" },
+ { 309, "HCI 13.10" },
+ { 310, "HCI 13.10" },
+ { 313, "HCI 14.4" },
+ { 314, "HCI 14.4" },
+ { 323, "HCI 14.5" },
+ { 324, "HCI 14.5" },
+ { 336, "HCI 14.6" },
+ { 337, "HCI 14.6" },
+ { 351, "HCI 13.11" },
+ { 352, "HCI 13.11" },
+ { 362, "HCI 15.0" },
+ { 363, "HCI 15.0" },
+ { 364, "HCI 15.0" },
+ { 365, "HCI 15.0" },
+ { 373, "HCI 14.7" },
+ { 374, "HCI 14.7" },
+ { 379, "HCI 15.1" },
+ { 380, "HCI 15.1" },
+ { 381, "HCI 15.1" },
+ { 382, "HCI 15.1" },
+ { 392, "HCI 15.2" },
+ { 393, "HCI 15.2" },
+ { 394, "HCI 15.2" },
+ { 395, "HCI 15.2" },
+ { 436, "HCI 16.0" },
+ { 437, "HCI 16.0" },
+ { 438, "HCI 16.0" },
+ { 439, "HCI 16.0" },
+ { 443, "HCI 15.3" },
+ { 444, "HCI 15.3" },
+ { 465, "HCI 16.1" },
+ { 466, "HCI 16.1" },
+ { 467, "HCI 16.1" },
+ { 468, "HCI 16.1" },
+ { 487, "HCI 14.8" },
+ { 488, "HCI 14.8" },
+ { 492, "HCI 16.2" },
+ { 493, "HCI 16.2" },
+ { 495, "HCI 16.2" },
+ { 496, "HCI 16.2" },
+ { 502, "HCI 16.1.1" },
+ { 503, "HCI 16.1.1" },
+ { 504, "HCI 16.1.1" },
+ { 505, "HCI 16.1.1" },
+ { 506, "HCI 16.1.2" },
+ { 507, "HCI 16.1.2" },
+ { 508, "HCI 16.1.2" },
+ { 509, "HCI 16.1.2" },
+ { 516, "HCI 16.3" },
+ { 517, "HCI 16.3" },
+ { 518, "HCI 16.3" },
+ { 519, "HCI 16.3" },
+ { 523, "HCI 16.4" },
+ { 524, "HCI 16.4" },
+ { 525, "HCI 16.4" },
+ { 526, "HCI 16.4" },
+ { 553, "HCI 15.3" },
+ { 554, "HCI 15.3" },
+ { 562, "HCI 16.5" },
+ { 563, "HCI 16.5" },
+ { 564, "HCI 16.5" },
+ { 565, "HCI 16.5" },
+ { 593, "HCI 17.0" },
+ { 594, "HCI 17.0" },
+ { 595, "HCI 17.0" },
+ { 599, "HCI 17.0" },
+ { 600, "HCI 17.0" },
+ { 608, "HCI 13.10.1" },
+ { 609, "HCI 13.10.1" },
+ { 613, "HCI 17.1" },
+ { 614, "HCI 17.1" },
+ { 615, "HCI 17.1" },
+ { 616, "HCI 17.1" },
+ { 618, "HCI 17.1" },
+ { 624, "HCI 17.2" },
+ { 625, "HCI 17.2" },
+ { 626, "HCI 17.2" },
+ { 627, "HCI 17.2" },
+ { 637, "HCI 16.6" },
+ { 638, "HCI 16.6" },
+ { 639, "HCI 16.6" },
+ { 640, "HCI 16.6" },
+ { 642, "HCI 13.10.2" },
+ { 643, "HCI 13.10.2" },
+ { 644, "HCI 13.10.3" },
+ { 645, "HCI 13.10.3" },
+ { 668, "HCI 13.10.4" },
+ { 669, "HCI 13.10.4" },
+ { 681, "HCI 16.7" },
+ { 682, "HCI 16.7" },
+ { 683, "HCI 16.7" },
+ { 684, "HCI 16.7" },
+ { 704, "HCI 16.8" },
+ { 718, "HCI 16.4.1" },
+ { 719, "HCI 16.4.1" },
+ { 720, "HCI 16.4.1" },
+ { 721, "HCI 16.4.1" },
+ { 722, "HCI 16.7.1" },
+ { 723, "HCI 16.7.1" },
+ { 724, "HCI 16.7.1" },
+ { 725, "HCI 16.7.1" },
+ { 731, "HCI 16.7.2" },
+ { 732, "HCI 16.7.2" },
+ { 733, "HCI 16.7.2" },
+ { 734, "HCI 16.7.2" },
+ { 735, "HCI 16.4.2" },
+ { 736, "HCI 16.4.2" },
+ { 737, "HCI 16.4.2" },
+ { 738, "HCI 16.4.2" },
+ { 750, "HCI 16.7.3" },
+ { 751, "HCI 16.7.3" },
+ { 752, "HCI 16.7.3" },
+ { 753, "HCI 16.7.3" },
+ { 760, "HCI 16.7.4" },
+ { 761, "HCI 16.7.4" },
+ { 762, "HCI 16.7.4" },
+ { 763, "HCI 16.7.4" },
+ { 770, "HCI 16.9" },
+ { 771, "HCI 16.9" },
+ { 772, "HCI 16.9" },
+ { 773, "HCI 16.9" },
+ { 774, "HCI 17.3" },
+ { 775, "HCI 17.3" },
+ { 776, "HCI 17.3" },
+ { 777, "HCI 17.3" },
+ { 781, "HCI 16.7.5" },
+ { 786, "HCI 16.10" },
+ { 787, "HCI 16.10" },
+ { 788, "HCI 16.10" },
+ { 789, "HCI 16.10" },
+ { 791, "HCI 16.4.3" },
+ { 792, "HCI 16.4.3" },
+ { 793, "HCI 16.4.3" },
+ { 794, "HCI 16.4.3" },
+ { 798, "HCI 16.11" },
+ { 799, "HCI 16.11" },
+ { 800, "HCI 16.11" },
+ { 801, "HCI 16.11" },
+ { 806, "HCI 16.7.5" },
+ { 807, "HCI 16.12" },
+ { 808, "HCI 16.12" },
+ { 809, "HCI 16.12" },
+ { 810, "HCI 16.12" },
+ { 817, "HCI 16.13" },
+ { 818, "HCI 16.13" },
+ { 819, "HCI 16.13" },
+ { 820, "HCI 16.13" },
+ { 823, "HCI 13.10.5" },
+ { 824, "HCI 13.10.5" },
+ { 826, "HCI 16.14" },
+ { 827, "HCI 16.14" },
+ { 828, "HCI 16.14" },
+ { 829, "HCI 16.14" },
+ { 843, "HCI 17.3.1" },
+ { 856, "HCI 17.3.2" },
+ { 857, "HCI 17.3.2" },
+ { 858, "HCI 17.3.2" },
+ { 1120, "HCI 17.11" },
+ { 1168, "HCI 18.1" },
+ { 1169, "HCI 18.1" },
+ { 1241, "HCI 18.x" },
+ { 1298, "HCI 18.2" },
+ { 1354, "HCI 18.2" },
+ { 1392, "HCI 18.2" },
+ { 1393, "HCI 18.2" },
+ { 1501, "HCI 18.2" },
+ { 1503, "HCI 18.2" },
+ { 1504, "HCI 18.2" },
+ { 1505, "HCI 18.2" },
+ { 1506, "HCI 18.2" },
+ { 1520, "HCI 18.2" },
+ { 1586, "HCI 18.2" },
+ { 1591, "HCI 18.2" },
+ { 1592, "HCI 18.2" },
+ { 1593, "HCI 18.2.1" },
+ { 1733, "HCI 18.3" },
+ { 1734, "HCI 18.3" },
+ { 1735, "HCI 18.3" },
+ { 1737, "HCI 18.3" },
+ { 1915, "HCI 19.2" },
+ { 1916, "HCI 19.2" },
+ { 1958, "HCI 19.2" },
+ { 1981, "Unified 20a" },
+ { 1982, "Unified 20a" },
+ { 1989, "HCI 18.4" },
+ { 2062, "Unified 20a1" },
+ { 2063, "Unified 20a1" },
+ { 2067, "Unified 18f" },
+ { 2068, "Unified 18f" },
+ { 2243, "Unified 18e" },
+ { 2244, "Unified 18e" },
+ { 2258, "Unified 20d" },
+ { 2259, "Unified 20d" },
+ { 2361, "Unified 20e" },
+ { 2362, "Unified 20e" },
+ { 2386, "Unified 21a" },
+ { 2387, "Unified 21a" },
+ { 2423, "Unified 21a" },
+ { 2424, "Unified 21a" },
+ { 2623, "Unified 21c" },
+ { 2624, "Unified 21c" },
+ { 2625, "Unified 21c" },
+ { 2626, "Unified 21c" },
+ { 2627, "Unified 21c" },
+ { 2628, "Unified 21c" },
+ { 2629, "Unified 21c" },
+ { 2630, "Unified 21c" },
+ { 2631, "Unified 21c" },
+ { 2632, "Unified 21c" },
+ { 2633, "Unified 21c" },
+ { 2634, "Unified 21c" },
+ { 2635, "Unified 21c" },
+ { 2636, "Unified 21c" },
+ { 2649, "Unified 21c" },
+ { 2650, "Unified 21c" },
+ { 2651, "Unified 21c" },
+ { 2652, "Unified 21c" },
+ { 2653, "Unified 21c" },
+ { 2654, "Unified 21c" },
+ { 2655, "Unified 21c" },
+ { 2656, "Unified 21c" },
+ { 2658, "Unified 21c" },
+ { 3057, "Unified 21d" },
+ { 3058, "Unified 21d" },
+ { 3059, "Unified 21d" },
+ { 3060, "Unified 21d" },
+ { 3062, "Unified 21d" },
+ { 3063, "Unified 21d" },
+ { 3064, "Unified 21d" },
+ { 3164, "Unified 21e" },
+ { 3413, "Unified 21f" },
+ { 3414, "Unified 21f" },
+ { 3415, "Unified 21f" },
+ { 3424, "Unified 21f" },
+ { 3454, "Unified 21f" },
+ { 3684, "Unified 21f" },
+ { 3764, "Unified 21f" },
+ { 4276, "Unified 22b" },
+ { 4277, "Unified 22b" },
+ { 4279, "Unified 22b" },
+ { 4281, "Unified 22b" },
+ { 4282, "Unified 22b" },
+ { 4283, "Unified 22b" },
+ { 4284, "Unified 22b" },
+ { 4285, "Unified 22b" },
+ { 4289, "Unified 22b" },
+ { 4290, "Unified 22b" },
+ { 4291, "Unified 22b" },
+ { 4292, "Unified 22b" },
+ { 4293, "Unified 22b" },
+ { 4294, "Unified 22b" },
+ { 4295, "Unified 22b" },
+ { 4363, "Unified 22c" },
+ { 4373, "Unified 22c" },
+ { 4374, "Unified 22c" },
+ { 4532, "Unified 22d" },
+ { 4533, "Unified 22d" },
+ { 4698, "Unified 23c" },
+ { 4839, "Unified 23c" },
+ { 4841, "Unified 23c" },
+ { 4866, "Unified 23c" },
+ { 4867, "Unified 23c" },
+ { 4868, "Unified 23c" },
+ { 4869, "Unified 23c" },
+ { 4870, "Unified 23c" },
+ { 4871, "Unified 23c" },
+ { 4872, "Unified 23c" },
+ { 4874, "Unified 23c" },
+ { 4875, "Unified 23c" },
+ { 4876, "Unified 23c" },
+ { 4877, "Unified 23c" },
+ { 2526, "Marcel 1 (2005-09-26)" },
+ { 2543, "Marcel 2 (2005-09-28)" },
+ { 2622, "Marcel 3 (2005-10-27)" },
+ { 3326, "Marcel 4 (2006-06-16)" },
+ { 3612, "Marcel 5 (2006-10-24)" },
+ { 4509, "Marcel 6 (2007-06-11)" },
+ { 195, "Sniff 1 (2001-11-27)" },
+ { 220, "Sniff 2 (2002-01-03)" },
+ { 269, "Sniff 3 (2002-02-22)" },
+ { 270, "Sniff 4 (2002-02-26)" },
+ { 284, "Sniff 5 (2002-03-12)" },
+ { 292, "Sniff 6 (2002-03-20)" },
+ { 305, "Sniff 7 (2002-04-12)" },
+ { 306, "Sniff 8 (2002-04-12)" },
+ { 343, "Sniff 9 (2002-05-02)" },
+ { 346, "Sniff 10 (2002-05-03)" },
+ { 355, "Sniff 11 (2002-05-16)" },
+ { 256, "Sniff 11 (2002-05-16)" },
+ { 390, "Sniff 12 (2002-06-26)" },
+ { 450, "Sniff 13 (2002-08-16)" },
+ { 451, "Sniff 13 (2002-08-16)" },
+ { 533, "Sniff 14 (2002-10-11)" },
+ { 580, "Sniff 15 (2002-11-14)" },
+ { 623, "Sniff 16 (2002-12-12)" },
+ { 678, "Sniff 17 (2003-01-29)" },
+ { 847, "Sniff 18 (2003-04-17)" },
+ { 876, "Sniff 19 (2003-06-10)" },
+ { 997, "Sniff 22 (2003-09-05)" },
+ { 1027, "Sniff 23 (2003-10-03)" },
+ { 1029, "Sniff 24 (2003-10-03)" },
+ { 1112, "Sniff 25 (2003-12-03)" },
+ { 1113, "Sniff 25 (2003-12-03)" },
+ { 1133, "Sniff 26 (2003-12-18)" },
+ { 1134, "Sniff 26 (2003-12-18)" },
+ { 1223, "Sniff 27 (2004-03-08)" },
+ { 1224, "Sniff 27 (2004-03-08)" },
+ { 1319, "Sniff 31 (2004-04-22)" },
+ { 1320, "Sniff 31 (2004-04-22)" },
+ { 1427, "Sniff 34 (2004-06-16)" },
+ { 1508, "Sniff 35 (2004-07-19)" },
+ { 1509, "Sniff 35 (2004-07-19)" },
+ { 1587, "Sniff 36 (2004-08-18)" },
+ { 1588, "Sniff 36 (2004-08-18)" },
+ { 1641, "Sniff 37 (2004-09-16)" },
+ { 1642, "Sniff 37 (2004-09-16)" },
+ { 1699, "Sniff 38 (2004-10-07)" },
+ { 1700, "Sniff 38 (2004-10-07)" },
+ { 1752, "Sniff 39 (2004-11-02)" },
+ { 1753, "Sniff 39 (2004-11-02)" },
+ { 1759, "Sniff 40 (2004-11-03)" },
+ { 1760, "Sniff 40 (2004-11-03)" },
+ { 1761, "Sniff 40 (2004-11-03)" },
+ { 2009, "Sniff 41 (2005-04-06)" },
+ { 2010, "Sniff 41 (2005-04-06)" },
+ { 2011, "Sniff 41 (2005-04-06)" },
+ { 2016, "Sniff 42 (2005-04-11)" },
+ { 2017, "Sniff 42 (2005-04-11)" },
+ { 2018, "Sniff 42 (2005-04-11)" },
+ { 2023, "Sniff 43 (2005-04-14)" },
+ { 2024, "Sniff 43 (2005-04-14)" },
+ { 2025, "Sniff 43 (2005-04-14)" },
+ { 2032, "Sniff 44 (2005-04-18)" },
+ { 2033, "Sniff 44 (2005-04-18)" },
+ { 2034, "Sniff 44 (2005-04-18)" },
+ { 2288, "Sniff 45 (2005-07-08)" },
+ { 2289, "Sniff 45 (2005-07-08)" },
+ { 2290, "Sniff 45 (2005-07-08)" },
+ { 2388, "Sniff 46 (2005-08-17)" },
+ { 2389, "Sniff 46 (2005-08-17)" },
+ { 2390, "Sniff 46 (2005-08-17)" },
+ { 2869, "Sniff 47 (2006-02-15)" },
+ { 2870, "Sniff 47 (2006-02-15)" },
+ { 2871, "Sniff 47 (2006-02-15)" },
+ { 3214, "Sniff 48 (2006-05-16)" },
+ { 3215, "Sniff 48 (2006-05-16)" },
+ { 3216, "Sniff 48 (2006-05-16)" },
+ { 3356, "Sniff 49 (2006-07-17)" },
+ { 3529, "Sniff 50 (2006-09-21)" },
+ { 3546, "Sniff 51 (2006-09-29)" },
+ { 3683, "Sniff 52 (2006-11-03)" },
+ { 0, }
+};
+
+char *csr_builddeftostr(uint16_t def)
+{
+ switch (def) {
+ case 0x0000:
+ return "NONE";
+ case 0x0001:
+ return "CHIP_BASE_BC01";
+ case 0x0002:
+ return "CHIP_BASE_BC02";
+ case 0x0003:
+ return "CHIP_BC01B";
+ case 0x0004:
+ return "CHIP_BC02_EXTERNAL";
+ case 0x0005:
+ return "BUILD_HCI";
+ case 0x0006:
+ return "BUILD_RFCOMM";
+ case 0x0007:
+ return "BT_VER_1_1";
+ case 0x0008:
+ return "TRANSPORT_ALL";
+ case 0x0009:
+ return "TRANSPORT_BCSP";
+ case 0x000a:
+ return "TRANSPORT_H4";
+ case 0x000b:
+ return "TRANSPORT_USB";
+ case 0x000c:
+ return "MAX_CRYPT_KEY_LEN_56";
+ case 0x000d:
+ return "MAX_CRYPT_KEY_LEN_128";
+ case 0x000e:
+ return "TRANSPORT_USER";
+ case 0x000f:
+ return "CHIP_BC02_KATO";
+ case 0x0010:
+ return "TRANSPORT_NONE";
+ case 0x0012:
+ return "REQUIRE_8MBIT";
+ case 0x0013:
+ return "RADIOTEST";
+ case 0x0014:
+ return "RADIOTEST_LITE";
+ case 0x0015:
+ return "INSTALL_FLASH";
+ case 0x0016:
+ return "INSTALL_EEPROM";
+ case 0x0017:
+ return "INSTALL_COMBO_DOT11";
+ case 0x0018:
+ return "LOWPOWER_TX";
+ case 0x0019:
+ return "TRANSPORT_TWUTL";
+ case 0x001a:
+ return "COMPILER_GCC";
+ case 0x001b:
+ return "CHIP_BC02_CLOUSEAU";
+ case 0x001c:
+ return "CHIP_BC02_TOULOUSE";
+ case 0x001d:
+ return "CHIP_BASE_BC3";
+ case 0x001e:
+ return "CHIP_BC3_NICKNACK";
+ case 0x001f:
+ return "CHIP_BC3_KALIMBA";
+ case 0x0020:
+ return "INSTALL_HCI_MODULE";
+ case 0x0021:
+ return "INSTALL_L2CAP_MODULE";
+ case 0x0022:
+ return "INSTALL_DM_MODULE";
+ case 0x0023:
+ return "INSTALL_SDP_MODULE";
+ case 0x0024:
+ return "INSTALL_RFCOMM_MODULE";
+ case 0x0025:
+ return "INSTALL_HIDIO_MODULE";
+ case 0x0026:
+ return "INSTALL_PAN_MODULE";
+ case 0x0027:
+ return "INSTALL_IPV4_MODULE";
+ case 0x0028:
+ return "INSTALL_IPV6_MODULE";
+ case 0x0029:
+ return "INSTALL_TCP_MODULE";
+ case 0x002a:
+ return "BT_VER_1_2";
+ case 0x002b:
+ return "INSTALL_UDP_MODULE";
+ case 0x002c:
+ return "REQUIRE_0_WAIT_STATES";
+ case 0x002d:
+ return "CHIP_BC3_PADDYWACK";
+ case 0x002e:
+ return "CHIP_BC4_COYOTE";
+ case 0x002f:
+ return "CHIP_BC4_ODDJOB";
+ case 0x0030:
+ return "TRANSPORT_H4DS";
+ case 0x0031:
+ return "CHIP_BASE_BC4";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+char *csr_buildidtostr(uint16_t id)
+{
+ static char str[12];
+ int i;
+
+ for (i = 0; csr_map[i].id; i++)
+ if (csr_map[i].id == id)
+ return csr_map[i].str;
+
+ snprintf(str, 11, "Build %d", id);
+ return str;
+}
+
+char *csr_chipvertostr(uint16_t ver, uint16_t rev)
+{
+ switch (ver) {
+ case 0x00:
+ return "BlueCore01a";
+ case 0x01:
+ switch (rev) {
+ case 0x64:
+ return "BlueCore01b (ES)";
+ case 0x65:
+ default:
+ return "BlueCore01b";
+ }
+ case 0x02:
+ switch (rev) {
+ case 0x89:
+ return "BlueCore02-External (ES2)";
+ case 0x8a:
+ return "BlueCore02-External";
+ case 0x28:
+ return "BlueCore02-ROM/Audio/Flash";
+ default:
+ return "BlueCore02";
+ }
+ case 0x03:
+ switch (rev) {
+ case 0x43:
+ return "BlueCore3-MM";
+ case 0x15:
+ return "BlueCore3-ROM";
+ case 0xe2:
+ return "BlueCore3-Flash";
+ case 0x26:
+ return "BlueCore4-External";
+ case 0x30:
+ return "BlueCore4-ROM";
+ default:
+ return "BlueCore3 or BlueCore4";
+ }
+ default:
+ return "Unknown";
+ }
+}
+
+char *csr_pskeytostr(uint16_t pskey)
+{
+ switch (pskey) {
+ case CSR_PSKEY_BDADDR:
+ return "Bluetooth address";
+ case CSR_PSKEY_COUNTRYCODE:
+ return "Country code";
+ case CSR_PSKEY_CLASSOFDEVICE:
+ return "Class of device";
+ case CSR_PSKEY_DEVICE_DRIFT:
+ return "Device drift";
+ case CSR_PSKEY_DEVICE_JITTER:
+ return "Device jitter";
+ case CSR_PSKEY_MAX_ACLS:
+ return "Maximum ACL links";
+ case CSR_PSKEY_MAX_SCOS:
+ return "Maximum SCO links";
+ case CSR_PSKEY_MAX_REMOTE_MASTERS:
+ return "Maximum remote masters";
+ case CSR_PSKEY_ENABLE_MASTERY_WITH_SLAVERY:
+ return "Support master and slave roles simultaneously";
+ case CSR_PSKEY_H_HC_FC_MAX_ACL_PKT_LEN:
+ return "Maximum HCI ACL packet length";
+ case CSR_PSKEY_H_HC_FC_MAX_SCO_PKT_LEN:
+ return "Maximum HCI SCO packet length";
+ case CSR_PSKEY_H_HC_FC_MAX_ACL_PKTS:
+ return "Maximum number of HCI ACL packets";
+ case CSR_PSKEY_H_HC_FC_MAX_SCO_PKTS:
+ return "Maximum number of HCI SCO packets";
+ case CSR_PSKEY_LC_FC_BUFFER_LOW_WATER_MARK:
+ return "Flow control low water mark";
+ case CSR_PSKEY_LC_MAX_TX_POWER:
+ return "Maximum transmit power";
+ case CSR_PSKEY_TX_GAIN_RAMP:
+ return "Transmit gain ramp rate";
+ case CSR_PSKEY_LC_POWER_TABLE:
+ return "Radio power table";
+ case CSR_PSKEY_LC_PEER_POWER_PERIOD:
+ return "Peer transmit power control interval";
+ case CSR_PSKEY_LC_FC_POOLS_LOW_WATER_MARK:
+ return "Flow control pool low water mark";
+ case CSR_PSKEY_LC_DEFAULT_TX_POWER:
+ return "Default transmit power";
+ case CSR_PSKEY_LC_RSSI_GOLDEN_RANGE:
+ return "RSSI at bottom of golden receive range";
+ case CSR_PSKEY_LC_COMBO_DISABLE_PIO_MASK:
+ return "Combo: PIO lines and logic to disable transmit";
+ case CSR_PSKEY_LC_COMBO_PRIORITY_PIO_MASK:
+ return "Combo: priority activity PIO lines and logic";
+ case CSR_PSKEY_LC_COMBO_DOT11_CHANNEL_PIO_BASE:
+ return "Combo: 802.11b channel number base PIO line";
+ case CSR_PSKEY_LC_COMBO_DOT11_BLOCK_CHANNELS:
+ return "Combo: channels to block either side of 802.11b";
+ case CSR_PSKEY_LC_MAX_TX_POWER_NO_RSSI:
+ return "Maximum transmit power when peer has no RSSI";
+ case CSR_PSKEY_LC_CONNECTION_RX_WINDOW:
+ return "Receive window size during connections";
+ case CSR_PSKEY_LC_COMBO_DOT11_TX_PROTECTION_MODE:
+ return "Combo: which TX packets shall we protect";
+ case CSR_PSKEY_LC_ENHANCED_POWER_TABLE:
+ return "Radio power table";
+ case CSR_PSKEY_LC_WIDEBAND_RSSI_CONFIG:
+ return "RSSI configuration for use with wideband RSSI";
+ case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_LEAD:
+ return "Combo: How much notice will we give the Combo Card";
+ case CSR_PSKEY_BT_CLOCK_INIT:
+ return "Initial value of Bluetooth clock";
+ case CSR_PSKEY_TX_MR_MOD_DELAY:
+ return "TX Mod delay";
+ case CSR_PSKEY_RX_MR_SYNC_TIMING:
+ return "RX MR Sync Timing";
+ case CSR_PSKEY_RX_MR_SYNC_CONFIG:
+ return "RX MR Sync Configuration";
+ case CSR_PSKEY_LC_LOST_SYNC_SLOTS:
+ return "Time in ms for lost sync in low power modes";
+ case CSR_PSKEY_RX_MR_SAMP_CONFIG:
+ return "RX MR Sync Configuration";
+ case CSR_PSKEY_AGC_HYST_LEVELS:
+ return "AGC hysteresis levels";
+ case CSR_PSKEY_RX_LEVEL_LOW_SIGNAL:
+ return "ANA_RX_LVL at low signal strengths";
+ case CSR_PSKEY_AGC_IQ_LVL_VALUES:
+ return "ANA_IQ_LVL values for AGC algorithmn";
+ case CSR_PSKEY_MR_FTRIM_OFFSET_12DB:
+ return "ANA_RX_FTRIM offset when using 12 dB IF atten ";
+ case CSR_PSKEY_MR_FTRIM_OFFSET_6DB:
+ return "ANA_RX_FTRIM offset when using 6 dB IF atten ";
+ case CSR_PSKEY_NO_CAL_ON_BOOT:
+ return "Do not calibrate radio on boot";
+ case CSR_PSKEY_RSSI_HI_TARGET:
+ return "RSSI high target";
+ case CSR_PSKEY_PREFERRED_MIN_ATTENUATION:
+ return "Preferred minimum attenuator setting";
+ case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_OVERRIDE:
+ return "Combo: Treat all packets as high priority";
+ case CSR_PSKEY_LC_MULTISLOT_HOLDOFF:
+ return "Time till single slot packets are used for resync";
+ case CSR_PSKEY_FREE_KEY_PIGEON_HOLE:
+ return "Link key store bitfield";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR0:
+ return "Bluetooth address + link key 0";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR1:
+ return "Bluetooth address + link key 1";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR2:
+ return "Bluetooth address + link key 2";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR3:
+ return "Bluetooth address + link key 3";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR4:
+ return "Bluetooth address + link key 4";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR5:
+ return "Bluetooth address + link key 5";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR6:
+ return "Bluetooth address + link key 6";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR7:
+ return "Bluetooth address + link key 7";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR8:
+ return "Bluetooth address + link key 8";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR9:
+ return "Bluetooth address + link key 9";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR10:
+ return "Bluetooth address + link key 10";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR11:
+ return "Bluetooth address + link key 11";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR12:
+ return "Bluetooth address + link key 12";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR13:
+ return "Bluetooth address + link key 13";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR14:
+ return "Bluetooth address + link key 14";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR15:
+ return "Bluetooth address + link key 15";
+ case CSR_PSKEY_ENC_KEY_LMIN:
+ return "Minimum encryption key length";
+ case CSR_PSKEY_ENC_KEY_LMAX:
+ return "Maximum encryption key length";
+ case CSR_PSKEY_LOCAL_SUPPORTED_FEATURES:
+ return "Local supported features block";
+ case CSR_PSKEY_LM_USE_UNIT_KEY:
+ return "Allow use of unit key for authentication?";
+ case CSR_PSKEY_HCI_NOP_DISABLE:
+ return "Disable the HCI Command_Status event on boot";
+ case CSR_PSKEY_LM_MAX_EVENT_FILTERS:
+ return "Maximum number of event filters";
+ case CSR_PSKEY_LM_USE_ENC_MODE_BROADCAST:
+ return "Allow LM to use enc_mode=2";
+ case CSR_PSKEY_LM_TEST_SEND_ACCEPTED_TWICE:
+ return "LM sends two LMP_accepted messages in test mode";
+ case CSR_PSKEY_LM_MAX_PAGE_HOLD_TIME:
+ return "Maximum time we hold a device around page";
+ case CSR_PSKEY_AFH_ADAPTATION_RESPONSE_TIME:
+ return "LM period for AFH adaption";
+ case CSR_PSKEY_AFH_OPTIONS:
+ return "Options to configure AFH";
+ case CSR_PSKEY_AFH_RSSI_RUN_PERIOD:
+ return "AFH RSSI reading period";
+ case CSR_PSKEY_AFH_REENABLE_CHANNEL_TIME:
+ return "AFH good channel adding time";
+ case CSR_PSKEY_NO_DROP_ON_ACR_MS_FAIL:
+ return "Complete link if acr barge-in role switch refused";
+ case CSR_PSKEY_MAX_PRIVATE_KEYS:
+ return "Max private link keys stored";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR0:
+ return "Bluetooth address + link key 0";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR1:
+ return "Bluetooth address + link key 1";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR2:
+ return "Bluetooth address + link key 2";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR3:
+ return "Bluetooth address + link key 3";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR4:
+ return "Bluetooth address + link key 4";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR5:
+ return "Bluetooth address + link key 5";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR6:
+ return "Bluetooth address + link key 6";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR7:
+ return "Bluetooth address + link key 7";
+ case CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS:
+ return "Local supported commands";
+ case CSR_PSKEY_LM_MAX_ABSENCE_INDEX:
+ return "Maximum absence index allowed";
+ case CSR_PSKEY_DEVICE_NAME:
+ return "Local device's \"user friendly\" name";
+ case CSR_PSKEY_AFH_RSSI_THRESHOLD:
+ return "AFH RSSI threshold";
+ case CSR_PSKEY_LM_CASUAL_SCAN_INTERVAL:
+ return "Scan interval in slots for casual scanning";
+ case CSR_PSKEY_AFH_MIN_MAP_CHANGE:
+ return "The minimum amount to change an AFH map by";
+ case CSR_PSKEY_AFH_RSSI_LP_RUN_PERIOD:
+ return "AFH RSSI reading period when in low power mode";
+ case CSR_PSKEY_HCI_LMP_LOCAL_VERSION:
+ return "The HCI and LMP version reported locally";
+ case CSR_PSKEY_LMP_REMOTE_VERSION:
+ return "The LMP version reported remotely";
+ case CSR_PSKEY_HOLD_ERROR_MESSAGE_NUMBER:
+ return "Maximum number of queued HCI Hardware Error Events";
+ case CSR_PSKEY_DFU_ATTRIBUTES:
+ return "DFU attributes";
+ case CSR_PSKEY_DFU_DETACH_TO:
+ return "DFU detach timeout";
+ case CSR_PSKEY_DFU_TRANSFER_SIZE:
+ return "DFU transfer size";
+ case CSR_PSKEY_DFU_ENABLE:
+ return "DFU enable";
+ case CSR_PSKEY_DFU_LIN_REG_ENABLE:
+ return "Linear Regulator enabled at boot in DFU mode";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_MSB:
+ return "DFU encryption VM application public key MSB";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_LSB:
+ return "DFU encryption VM application public key LSB";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_M_DASH:
+ return "DFU encryption VM application M dash";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_MSB:
+ return "DFU encryption VM application public key R2N MSB";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_LSB:
+ return "DFU encryption VM application public key R2N LSB";
+ case CSR_PSKEY_BCSP_LM_PS_BLOCK:
+ return "BCSP link establishment block";
+ case CSR_PSKEY_HOSTIO_FC_PS_BLOCK:
+ return "HCI flow control block";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO0:
+ return "Host transport channel 0 settings (BCSP ACK)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO1:
+ return "Host transport channel 1 settings (BCSP-LE)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO2:
+ return "Host transport channel 2 settings (BCCMD)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO3:
+ return "Host transport channel 3 settings (HQ)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO4:
+ return "Host transport channel 4 settings (DM)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO5:
+ return "Host transport channel 5 settings (HCI CMD/EVT)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO6:
+ return "Host transport channel 6 settings (HCI ACL)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO7:
+ return "Host transport channel 7 settings (HCI SCO)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO8:
+ return "Host transport channel 8 settings (L2CAP)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO9:
+ return "Host transport channel 9 settings (RFCOMM)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO10:
+ return "Host transport channel 10 settings (SDP)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO11:
+ return "Host transport channel 11 settings (TEST)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO12:
+ return "Host transport channel 12 settings (DFU)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO13:
+ return "Host transport channel 13 settings (VM)";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO14:
+ return "Host transport channel 14 settings";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO15:
+ return "Host transport channel 15 settings";
+ case CSR_PSKEY_HOSTIO_UART_RESET_TIMEOUT:
+ return "UART reset counter timeout";
+ case CSR_PSKEY_HOSTIO_USE_HCI_EXTN:
+ return "Use hci_extn to route non-hci channels";
+ case CSR_PSKEY_HOSTIO_USE_HCI_EXTN_CCFC:
+ return "Use command-complete flow control for hci_extn";
+ case CSR_PSKEY_HOSTIO_HCI_EXTN_PAYLOAD_SIZE:
+ return "Maximum hci_extn payload size";
+ case CSR_PSKEY_BCSP_LM_CNF_CNT_LIMIT:
+ return "BCSP link establishment conf message count";
+ case CSR_PSKEY_HOSTIO_MAP_SCO_PCM:
+ return "Map SCO over PCM";
+ case CSR_PSKEY_HOSTIO_AWKWARD_PCM_SYNC:
+ return "PCM interface synchronisation is difficult";
+ case CSR_PSKEY_HOSTIO_BREAK_POLL_PERIOD:
+ return "Break poll period (microseconds)";
+ case CSR_PSKEY_HOSTIO_MIN_UART_HCI_SCO_SIZE:
+ return "Minimum SCO packet size sent to host over UART HCI";
+ case CSR_PSKEY_HOSTIO_MAP_SCO_CODEC:
+ return "Map SCO over the built-in codec";
+ case CSR_PSKEY_PCM_CVSD_TX_HI_FREQ_BOOST:
+ return "High frequency boost for PCM when transmitting CVSD";
+ case CSR_PSKEY_PCM_CVSD_RX_HI_FREQ_BOOST:
+ return "High frequency boost for PCM when receiving CVSD";
+ case CSR_PSKEY_PCM_CONFIG32:
+ return "PCM interface settings bitfields";
+ case CSR_PSKEY_USE_OLD_BCSP_LE:
+ return "Use the old version of BCSP link establishment";
+ case CSR_PSKEY_PCM_CVSD_USE_NEW_FILTER:
+ return "CVSD uses the new filter if available";
+ case CSR_PSKEY_PCM_FORMAT:
+ return "PCM data format";
+ case CSR_PSKEY_CODEC_OUT_GAIN:
+ return "Audio output gain when using built-in codec";
+ case CSR_PSKEY_CODEC_IN_GAIN:
+ return "Audio input gain when using built-in codec";
+ case CSR_PSKEY_CODEC_PIO:
+ return "PIO to enable when built-in codec is enabled";
+ case CSR_PSKEY_PCM_LOW_JITTER_CONFIG:
+ return "PCM interface settings for low jitter master mode";
+ case CSR_PSKEY_HOSTIO_SCO_PCM_THRESHOLDS:
+ return "Thresholds for SCO PCM buffers";
+ case CSR_PSKEY_HOSTIO_SCO_HCI_THRESHOLDS:
+ return "Thresholds for SCO HCI buffers";
+ case CSR_PSKEY_HOSTIO_MAP_SCO_PCM_SLOT:
+ return "Route SCO data to specified slot in pcm frame";
+ case CSR_PSKEY_UART_BAUDRATE:
+ return "UART Baud rate";
+ case CSR_PSKEY_UART_CONFIG_BCSP:
+ return "UART configuration when using BCSP";
+ case CSR_PSKEY_UART_CONFIG_H4:
+ return "UART configuration when using H4";
+ case CSR_PSKEY_UART_CONFIG_H5:
+ return "UART configuration when using H5";
+ case CSR_PSKEY_UART_CONFIG_USR:
+ return "UART configuration when under VM control";
+ case CSR_PSKEY_UART_TX_CRCS:
+ return "Use CRCs for BCSP or H5";
+ case CSR_PSKEY_UART_ACK_TIMEOUT:
+ return "Acknowledgement timeout for BCSP and H5";
+ case CSR_PSKEY_UART_TX_MAX_ATTEMPTS:
+ return "Max times to send reliable BCSP or H5 message";
+ case CSR_PSKEY_UART_TX_WINDOW_SIZE:
+ return "Transmit window size for BCSP and H5";
+ case CSR_PSKEY_UART_HOST_WAKE:
+ return "UART host wakeup";
+ case CSR_PSKEY_HOSTIO_THROTTLE_TIMEOUT:
+ return "Host interface performance control.";
+ case CSR_PSKEY_PCM_ALWAYS_ENABLE:
+ return "PCM port is always enable when chip is running";
+ case CSR_PSKEY_UART_HOST_WAKE_SIGNAL:
+ return "Signal to use for uart host wakeup protocol";
+ case CSR_PSKEY_UART_CONFIG_H4DS:
+ return "UART configuration when using H4DS";
+ case CSR_PSKEY_H4DS_WAKE_DURATION:
+ return "How long to spend waking the host when using H4DS";
+ case CSR_PSKEY_H4DS_MAXWU:
+ return "Maximum number of H4DS Wake-Up messages to send";
+ case CSR_PSKEY_H4DS_LE_TIMER_PERIOD:
+ return "H4DS Link Establishment Tsync and Tconf period";
+ case CSR_PSKEY_H4DS_TWU_TIMER_PERIOD:
+ return "H4DS Twu timer period";
+ case CSR_PSKEY_H4DS_UART_IDLE_TIMER_PERIOD:
+ return "H4DS Tuart_idle timer period";
+ case CSR_PSKEY_ANA_FTRIM:
+ return "Crystal frequency trim";
+ case CSR_PSKEY_WD_TIMEOUT:
+ return "Watchdog timeout (microseconds)";
+ case CSR_PSKEY_WD_PERIOD:
+ return "Watchdog period (microseconds)";
+ case CSR_PSKEY_HOST_INTERFACE:
+ return "Host interface";
+ case CSR_PSKEY_HQ_HOST_TIMEOUT:
+ return "HQ host command timeout";
+ case CSR_PSKEY_HQ_ACTIVE:
+ return "Enable host query task?";
+ case CSR_PSKEY_BCCMD_SECURITY_ACTIVE:
+ return "Enable configuration security";
+ case CSR_PSKEY_ANA_FREQ:
+ return "Crystal frequency";
+ case CSR_PSKEY_PIO_PROTECT_MASK:
+ return "Access to PIO pins";
+ case CSR_PSKEY_PMALLOC_SIZES:
+ return "pmalloc sizes array";
+ case CSR_PSKEY_UART_BAUD_RATE:
+ return "UART Baud rate (pre 18)";
+ case CSR_PSKEY_UART_CONFIG:
+ return "UART configuration bitfield";
+ case CSR_PSKEY_STUB:
+ return "Stub";
+ case CSR_PSKEY_TXRX_PIO_CONTROL:
+ return "TX and RX PIO control";
+ case CSR_PSKEY_ANA_RX_LEVEL:
+ return "ANA_RX_LVL register initial value";
+ case CSR_PSKEY_ANA_RX_FTRIM:
+ return "ANA_RX_FTRIM register initial value";
+ case CSR_PSKEY_PSBC_DATA_VERSION:
+ return "Persistent store version";
+ case CSR_PSKEY_PCM0_ATTENUATION:
+ return "Volume control on PCM channel 0";
+ case CSR_PSKEY_LO_LVL_MAX:
+ return "Maximum value of LO level control register";
+ case CSR_PSKEY_LO_ADC_AMPL_MIN:
+ return "Minimum value of the LO amplitude measured on the ADC";
+ case CSR_PSKEY_LO_ADC_AMPL_MAX:
+ return "Maximum value of the LO amplitude measured on the ADC";
+ case CSR_PSKEY_IQ_TRIM_CHANNEL:
+ return "IQ calibration channel";
+ case CSR_PSKEY_IQ_TRIM_GAIN:
+ return "IQ calibration gain";
+ case CSR_PSKEY_IQ_TRIM_ENABLE:
+ return "IQ calibration enable";
+ case CSR_PSKEY_TX_OFFSET_HALF_MHZ:
+ return "Transmit offset";
+ case CSR_PSKEY_GBL_MISC_ENABLES:
+ return "Global miscellaneous hardware enables";
+ case CSR_PSKEY_UART_SLEEP_TIMEOUT:
+ return "Time in ms to deep sleep if nothing received";
+ case CSR_PSKEY_DEEP_SLEEP_STATE:
+ return "Deep sleep state usage";
+ case CSR_PSKEY_IQ_ENABLE_PHASE_TRIM:
+ return "IQ phase enable";
+ case CSR_PSKEY_HCI_HANDLE_FREEZE_PERIOD:
+ return "Time for which HCI handle is frozen after link removal";
+ case CSR_PSKEY_MAX_FROZEN_HCI_HANDLES:
+ return "Maximum number of frozen HCI handles";
+ case CSR_PSKEY_PAGETABLE_DESTRUCTION_DELAY:
+ return "Delay from freezing buf handle to deleting page table";
+ case CSR_PSKEY_IQ_TRIM_PIO_SETTINGS:
+ return "IQ PIO settings";
+ case CSR_PSKEY_USE_EXTERNAL_CLOCK:
+ return "Device uses an external clock";
+ case CSR_PSKEY_DEEP_SLEEP_WAKE_CTS:
+ return "Exit deep sleep on CTS line activity";
+ case CSR_PSKEY_FC_HC2H_FLUSH_DELAY:
+ return "Delay from disconnect to flushing HC->H FC tokens";
+ case CSR_PSKEY_RX_HIGHSIDE:
+ return "Disable the HIGHSIDE bit in ANA_CONFIG";
+ case CSR_PSKEY_TX_PRE_LVL:
+ return "TX pre-amplifier level";
+ case CSR_PSKEY_RX_SINGLE_ENDED:
+ return "RX single ended";
+ case CSR_PSKEY_TX_FILTER_CONFIG:
+ return "TX filter configuration";
+ case CSR_PSKEY_CLOCK_REQUEST_ENABLE:
+ return "External clock request enable";
+ case CSR_PSKEY_RX_MIN_ATTEN:
+ return "Minimum attenuation allowed for receiver";
+ case CSR_PSKEY_XTAL_TARGET_AMPLITUDE:
+ return "Crystal target amplitude";
+ case CSR_PSKEY_PCM_MIN_CPU_CLOCK:
+ return "Minimum CPU clock speed with PCM port running";
+ case CSR_PSKEY_HOST_INTERFACE_PIO_USB:
+ return "USB host interface selection PIO line";
+ case CSR_PSKEY_CPU_IDLE_MODE:
+ return "CPU idle mode when radio is active";
+ case CSR_PSKEY_DEEP_SLEEP_CLEAR_RTS:
+ return "Deep sleep clears the UART RTS line";
+ case CSR_PSKEY_RF_RESONANCE_TRIM:
+ return "Frequency trim for IQ and LNA resonant circuits";
+ case CSR_PSKEY_DEEP_SLEEP_PIO_WAKE:
+ return "PIO line to wake the chip from deep sleep";
+ case CSR_PSKEY_DRAIN_BORE_TIMERS:
+ return "Energy consumption measurement settings";
+ case CSR_PSKEY_DRAIN_TX_POWER_BASE:
+ return "Energy consumption measurement settings";
+ case CSR_PSKEY_MODULE_ID:
+ return "Module serial number";
+ case CSR_PSKEY_MODULE_DESIGN:
+ return "Module design ID";
+ case CSR_PSKEY_MODULE_SECURITY_CODE:
+ return "Module security code";
+ case CSR_PSKEY_VM_DISABLE:
+ return "VM disable";
+ case CSR_PSKEY_MOD_MANUF0:
+ return "Module manufactuer data 0";
+ case CSR_PSKEY_MOD_MANUF1:
+ return "Module manufactuer data 1";
+ case CSR_PSKEY_MOD_MANUF2:
+ return "Module manufactuer data 2";
+ case CSR_PSKEY_MOD_MANUF3:
+ return "Module manufactuer data 3";
+ case CSR_PSKEY_MOD_MANUF4:
+ return "Module manufactuer data 4";
+ case CSR_PSKEY_MOD_MANUF5:
+ return "Module manufactuer data 5";
+ case CSR_PSKEY_MOD_MANUF6:
+ return "Module manufactuer data 6";
+ case CSR_PSKEY_MOD_MANUF7:
+ return "Module manufactuer data 7";
+ case CSR_PSKEY_MOD_MANUF8:
+ return "Module manufactuer data 8";
+ case CSR_PSKEY_MOD_MANUF9:
+ return "Module manufactuer data 9";
+ case CSR_PSKEY_DUT_VM_DISABLE:
+ return "VM disable when entering radiotest modes";
+ case CSR_PSKEY_USR0:
+ return "User configuration data 0";
+ case CSR_PSKEY_USR1:
+ return "User configuration data 1";
+ case CSR_PSKEY_USR2:
+ return "User configuration data 2";
+ case CSR_PSKEY_USR3:
+ return "User configuration data 3";
+ case CSR_PSKEY_USR4:
+ return "User configuration data 4";
+ case CSR_PSKEY_USR5:
+ return "User configuration data 5";
+ case CSR_PSKEY_USR6:
+ return "User configuration data 6";
+ case CSR_PSKEY_USR7:
+ return "User configuration data 7";
+ case CSR_PSKEY_USR8:
+ return "User configuration data 8";
+ case CSR_PSKEY_USR9:
+ return "User configuration data 9";
+ case CSR_PSKEY_USR10:
+ return "User configuration data 10";
+ case CSR_PSKEY_USR11:
+ return "User configuration data 11";
+ case CSR_PSKEY_USR12:
+ return "User configuration data 12";
+ case CSR_PSKEY_USR13:
+ return "User configuration data 13";
+ case CSR_PSKEY_USR14:
+ return "User configuration data 14";
+ case CSR_PSKEY_USR15:
+ return "User configuration data 15";
+ case CSR_PSKEY_USR16:
+ return "User configuration data 16";
+ case CSR_PSKEY_USR17:
+ return "User configuration data 17";
+ case CSR_PSKEY_USR18:
+ return "User configuration data 18";
+ case CSR_PSKEY_USR19:
+ return "User configuration data 19";
+ case CSR_PSKEY_USR20:
+ return "User configuration data 20";
+ case CSR_PSKEY_USR21:
+ return "User configuration data 21";
+ case CSR_PSKEY_USR22:
+ return "User configuration data 22";
+ case CSR_PSKEY_USR23:
+ return "User configuration data 23";
+ case CSR_PSKEY_USR24:
+ return "User configuration data 24";
+ case CSR_PSKEY_USR25:
+ return "User configuration data 25";
+ case CSR_PSKEY_USR26:
+ return "User configuration data 26";
+ case CSR_PSKEY_USR27:
+ return "User configuration data 27";
+ case CSR_PSKEY_USR28:
+ return "User configuration data 28";
+ case CSR_PSKEY_USR29:
+ return "User configuration data 29";
+ case CSR_PSKEY_USR30:
+ return "User configuration data 30";
+ case CSR_PSKEY_USR31:
+ return "User configuration data 31";
+ case CSR_PSKEY_USR32:
+ return "User configuration data 32";
+ case CSR_PSKEY_USR33:
+ return "User configuration data 33";
+ case CSR_PSKEY_USR34:
+ return "User configuration data 34";
+ case CSR_PSKEY_USR35:
+ return "User configuration data 35";
+ case CSR_PSKEY_USR36:
+ return "User configuration data 36";
+ case CSR_PSKEY_USR37:
+ return "User configuration data 37";
+ case CSR_PSKEY_USR38:
+ return "User configuration data 38";
+ case CSR_PSKEY_USR39:
+ return "User configuration data 39";
+ case CSR_PSKEY_USR40:
+ return "User configuration data 40";
+ case CSR_PSKEY_USR41:
+ return "User configuration data 41";
+ case CSR_PSKEY_USR42:
+ return "User configuration data 42";
+ case CSR_PSKEY_USR43:
+ return "User configuration data 43";
+ case CSR_PSKEY_USR44:
+ return "User configuration data 44";
+ case CSR_PSKEY_USR45:
+ return "User configuration data 45";
+ case CSR_PSKEY_USR46:
+ return "User configuration data 46";
+ case CSR_PSKEY_USR47:
+ return "User configuration data 47";
+ case CSR_PSKEY_USR48:
+ return "User configuration data 48";
+ case CSR_PSKEY_USR49:
+ return "User configuration data 49";
+ case CSR_PSKEY_USB_VERSION:
+ return "USB specification version number";
+ case CSR_PSKEY_USB_DEVICE_CLASS_CODES:
+ return "USB device class codes";
+ case CSR_PSKEY_USB_VENDOR_ID:
+ return "USB vendor identifier";
+ case CSR_PSKEY_USB_PRODUCT_ID:
+ return "USB product identifier";
+ case CSR_PSKEY_USB_MANUF_STRING:
+ return "USB manufacturer string";
+ case CSR_PSKEY_USB_PRODUCT_STRING:
+ return "USB product string";
+ case CSR_PSKEY_USB_SERIAL_NUMBER_STRING:
+ return "USB serial number string";
+ case CSR_PSKEY_USB_CONFIG_STRING:
+ return "USB configuration string";
+ case CSR_PSKEY_USB_ATTRIBUTES:
+ return "USB attributes bitmap";
+ case CSR_PSKEY_USB_MAX_POWER:
+ return "USB device maximum power consumption";
+ case CSR_PSKEY_USB_BT_IF_CLASS_CODES:
+ return "USB Bluetooth interface class codes";
+ case CSR_PSKEY_USB_LANGID:
+ return "USB language strings supported";
+ case CSR_PSKEY_USB_DFU_CLASS_CODES:
+ return "USB DFU class codes block";
+ case CSR_PSKEY_USB_DFU_PRODUCT_ID:
+ return "USB DFU product ID";
+ case CSR_PSKEY_USB_PIO_DETACH:
+ return "USB detach/attach PIO line";
+ case CSR_PSKEY_USB_PIO_WAKEUP:
+ return "USB wakeup PIO line";
+ case CSR_PSKEY_USB_PIO_PULLUP:
+ return "USB D+ pullup PIO line";
+ case CSR_PSKEY_USB_PIO_VBUS:
+ return "USB VBus detection PIO Line";
+ case CSR_PSKEY_USB_PIO_WAKE_TIMEOUT:
+ return "Timeout for assertion of USB PIO wake signal";
+ case CSR_PSKEY_USB_PIO_RESUME:
+ return "PIO signal used in place of bus resume";
+ case CSR_PSKEY_USB_BT_SCO_IF_CLASS_CODES:
+ return "USB Bluetooth SCO interface class codes";
+ case CSR_PSKEY_USB_SUSPEND_PIO_LEVEL:
+ return "USB PIO levels to set when suspended";
+ case CSR_PSKEY_USB_SUSPEND_PIO_DIR:
+ return "USB PIO I/O directions to set when suspended";
+ case CSR_PSKEY_USB_SUSPEND_PIO_MASK:
+ return "USB PIO lines to be set forcibly in suspend";
+ case CSR_PSKEY_USB_ENDPOINT_0_MAX_PACKET_SIZE:
+ return "The maxmimum packet size for USB endpoint 0";
+ case CSR_PSKEY_USB_CONFIG:
+ return "USB config params for new chips (>bc2)";
+ case CSR_PSKEY_RADIOTEST_ATTEN_INIT:
+ return "Radio test initial attenuator";
+ case CSR_PSKEY_RADIOTEST_FIRST_TRIM_TIME:
+ return "IQ first calibration period in test";
+ case CSR_PSKEY_RADIOTEST_SUBSEQUENT_TRIM_TIME:
+ return "IQ subsequent calibration period in test";
+ case CSR_PSKEY_RADIOTEST_LO_LVL_TRIM_ENABLE:
+ return "LO_LVL calibration enable";
+ case CSR_PSKEY_RADIOTEST_DISABLE_MODULATION:
+ return "Disable modulation during radiotest transmissions";
+ case CSR_PSKEY_RFCOMM_FCON_THRESHOLD:
+ return "RFCOMM aggregate flow control on threshold";
+ case CSR_PSKEY_RFCOMM_FCOFF_THRESHOLD:
+ return "RFCOMM aggregate flow control off threshold";
+ case CSR_PSKEY_IPV6_STATIC_ADDR:
+ return "Static IPv6 address";
+ case CSR_PSKEY_IPV4_STATIC_ADDR:
+ return "Static IPv4 address";
+ case CSR_PSKEY_IPV6_STATIC_PREFIX_LEN:
+ return "Static IPv6 prefix length";
+ case CSR_PSKEY_IPV6_STATIC_ROUTER_ADDR:
+ return "Static IPv6 router address";
+ case CSR_PSKEY_IPV4_STATIC_SUBNET_MASK:
+ return "Static IPv4 subnet mask";
+ case CSR_PSKEY_IPV4_STATIC_ROUTER_ADDR:
+ return "Static IPv4 router address";
+ case CSR_PSKEY_MDNS_NAME:
+ return "Multicast DNS name";
+ case CSR_PSKEY_FIXED_PIN:
+ return "Fixed PIN";
+ case CSR_PSKEY_MDNS_PORT:
+ return "Multicast DNS port";
+ case CSR_PSKEY_MDNS_TTL:
+ return "Multicast DNS TTL";
+ case CSR_PSKEY_MDNS_IPV4_ADDR:
+ return "Multicast DNS IPv4 address";
+ case CSR_PSKEY_ARP_CACHE_TIMEOUT:
+ return "ARP cache timeout";
+ case CSR_PSKEY_HFP_POWER_TABLE:
+ return "HFP power table";
+ case CSR_PSKEY_DRAIN_BORE_TIMER_COUNTERS:
+ return "Energy consumption estimation timer counters";
+ case CSR_PSKEY_DRAIN_BORE_COUNTERS:
+ return "Energy consumption estimation counters";
+ case CSR_PSKEY_LOOP_FILTER_TRIM:
+ return "Trim value to optimise loop filter";
+ case CSR_PSKEY_DRAIN_BORE_CURRENT_PEAK:
+ return "Energy consumption estimation current peak";
+ case CSR_PSKEY_VM_E2_CACHE_LIMIT:
+ return "Maximum RAM for caching EEPROM VM application";
+ case CSR_PSKEY_FORCE_16MHZ_REF_PIO:
+ return "PIO line to force 16 MHz reference to be assumed";
+ case CSR_PSKEY_CDMA_LO_REF_LIMITS:
+ return "Local oscillator frequency reference limits for CDMA";
+ case CSR_PSKEY_CDMA_LO_ERROR_LIMITS:
+ return "Local oscillator frequency error limits for CDMA";
+ case CSR_PSKEY_CLOCK_STARTUP_DELAY:
+ return "Clock startup delay in milliseconds";
+ case CSR_PSKEY_DEEP_SLEEP_CORRECTION_FACTOR:
+ return "Deep sleep clock correction factor";
+ case CSR_PSKEY_TEMPERATURE_CALIBRATION:
+ return "Temperature in deg C for a given internal setting";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA:
+ return "Temperature for given internal PA adjustment";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL:
+ return "Temperature for a given TX_PRE_LVL adjustment";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB:
+ return "Temperature for a given TX_BB adjustment";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_ANA_FTRIM:
+ return "Temperature for given crystal trim adjustment";
+ case CSR_PSKEY_TEST_DELTA_OFFSET:
+ return "Frequency offset applied to synthesiser in test mode";
+ case CSR_PSKEY_RX_DYNAMIC_LVL_OFFSET:
+ return "Receiver dynamic level offset depending on channel";
+ case CSR_PSKEY_TEST_FORCE_OFFSET:
+ return "Force use of exact value in PSKEY_TEST_DELTA_OFFSET";
+ case CSR_PSKEY_RF_TRAP_BAD_DIVISION_RATIOS:
+ return "Trap bad division ratios in radio frequency tables";
+ case CSR_PSKEY_RADIOTEST_CDMA_LO_REF_LIMITS:
+ return "LO frequency reference limits for CDMA in radiotest";
+ case CSR_PSKEY_INITIAL_BOOTMODE:
+ return "Initial device bootmode";
+ case CSR_PSKEY_ONCHIP_HCI_CLIENT:
+ return "HCI traffic routed internally";
+ case CSR_PSKEY_RX_ATTEN_BACKOFF:
+ return "Receiver attenuation back-off";
+ case CSR_PSKEY_RX_ATTEN_UPDATE_RATE:
+ return "Receiver attenuation update rate";
+ case CSR_PSKEY_SYNTH_TXRX_THRESHOLDS:
+ return "Local oscillator tuning voltage limits for tx and rx";
+ case CSR_PSKEY_MIN_WAIT_STATES:
+ return "Flash wait state indicator";
+ case CSR_PSKEY_RSSI_CORRECTION:
+ return "RSSI correction factor.";
+ case CSR_PSKEY_SCHED_THROTTLE_TIMEOUT:
+ return "Scheduler performance control.";
+ case CSR_PSKEY_DEEP_SLEEP_USE_EXTERNAL_CLOCK:
+ return "Deep sleep uses external 32 kHz clock source";
+ case CSR_PSKEY_TRIM_RADIO_FILTERS:
+ return "Trim rx and tx radio filters if true.";
+ case CSR_PSKEY_TRANSMIT_OFFSET:
+ return "Transmit offset in units of 62.5 kHz";
+ case CSR_PSKEY_USB_VM_CONTROL:
+ return "VM application will supply USB descriptors";
+ case CSR_PSKEY_MR_ANA_RX_FTRIM:
+ return "Medium rate value for the ANA_RX_FTRIM register";
+ case CSR_PSKEY_I2C_CONFIG:
+ return "I2C configuration";
+ case CSR_PSKEY_IQ_LVL_RX:
+ return "IQ demand level for reception";
+ case CSR_PSKEY_MR_TX_FILTER_CONFIG:
+ return "TX filter configuration used for enhanced data rate";
+ case CSR_PSKEY_MR_TX_CONFIG2:
+ return "TX filter configuration used for enhanced data rate";
+ case CSR_PSKEY_USB_DONT_RESET_BOOTMODE_ON_HOST_RESET:
+ return "Don't reset bootmode if USB host resets";
+ case CSR_PSKEY_LC_USE_THROTTLING:
+ return "Adjust packet selection on packet error rate";
+ case CSR_PSKEY_CHARGER_TRIM:
+ return "Trim value for the current charger";
+ case CSR_PSKEY_CLOCK_REQUEST_FEATURES:
+ return "Clock request is tristated if enabled";
+ case CSR_PSKEY_TRANSMIT_OFFSET_CLASS1:
+ return "Transmit offset / 62.5 kHz for class 1 radios";
+ case CSR_PSKEY_TX_AVOID_PA_CLASS1_PIO:
+ return "PIO line asserted in class1 operation to avoid PA";
+ case CSR_PSKEY_MR_PIO_CONFIG:
+ return "PIO line asserted in class1 operation to avoid PA";
+ case CSR_PSKEY_UART_CONFIG2:
+ return "The UART Sampling point";
+ case CSR_PSKEY_CLASS1_IQ_LVL:
+ return "IQ demand level for class 1 power level";
+ case CSR_PSKEY_CLASS1_TX_CONFIG2:
+ return "TX filter configuration used for class 1 tx power";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1:
+ return "Temperature for given internal PA adjustment";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1:
+ return "Temperature for given internal PA adjustment";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR:
+ return "Temperature adjustment for TX_PRE_LVL in EDR";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER:
+ return "Temperature for a given TX_BB in EDR header";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD:
+ return "Temperature for a given TX_BB in EDR payload";
+ case CSR_PSKEY_RX_MR_EQ_TAPS:
+ return "Adjust receiver configuration for EDR";
+ case CSR_PSKEY_TX_PRE_LVL_CLASS1:
+ return "TX pre-amplifier level in class 1 operation";
+ case CSR_PSKEY_ANALOGUE_ATTENUATOR:
+ return "TX analogue attenuator setting";
+ case CSR_PSKEY_MR_RX_FILTER_TRIM:
+ return "Trim for receiver used in EDR.";
+ case CSR_PSKEY_MR_RX_FILTER_RESPONSE:
+ return "Filter response for receiver used in EDR.";
+ case CSR_PSKEY_PIO_WAKEUP_STATE:
+ return "PIO deep sleep wake up state ";
+ case CSR_PSKEY_MR_TX_IF_ATTEN_OFF_TEMP:
+ return "TX IF atten off temperature when using EDR.";
+ case CSR_PSKEY_LO_DIV_LATCH_BYPASS:
+ return "Bypass latch for LO dividers";
+ case CSR_PSKEY_LO_VCO_STANDBY:
+ return "Use standby mode for the LO VCO";
+ case CSR_PSKEY_SLOW_CLOCK_FILTER_SHIFT:
+ return "Slow clock sampling filter constant";
+ case CSR_PSKEY_SLOW_CLOCK_FILTER_DIVIDER:
+ return "Slow clock filter fractional threshold";
+ case CSR_PSKEY_USB_ATTRIBUTES_POWER:
+ return "USB self powered";
+ case CSR_PSKEY_USB_ATTRIBUTES_WAKEUP:
+ return "USB responds to wake-up";
+ case CSR_PSKEY_DFU_ATTRIBUTES_MANIFESTATION_TOLERANT:
+ return "DFU manifestation tolerant";
+ case CSR_PSKEY_DFU_ATTRIBUTES_CAN_UPLOAD:
+ return "DFU can upload";
+ case CSR_PSKEY_DFU_ATTRIBUTES_CAN_DOWNLOAD:
+ return "DFU can download";
+ case CSR_PSKEY_UART_CONFIG_STOP_BITS:
+ return "UART: stop bits";
+ case CSR_PSKEY_UART_CONFIG_PARITY_BIT:
+ return "UART: parity bit";
+ case CSR_PSKEY_UART_CONFIG_FLOW_CTRL_EN:
+ return "UART: hardware flow control";
+ case CSR_PSKEY_UART_CONFIG_RTS_AUTO_EN:
+ return "UART: RTS auto-enabled";
+ case CSR_PSKEY_UART_CONFIG_RTS:
+ return "UART: RTS asserted";
+ case CSR_PSKEY_UART_CONFIG_TX_ZERO_EN:
+ return "UART: TX zero enable";
+ case CSR_PSKEY_UART_CONFIG_NON_BCSP_EN:
+ return "UART: enable BCSP-specific hardware";
+ case CSR_PSKEY_UART_CONFIG_RX_RATE_DELAY:
+ return "UART: RX rate delay";
+ case CSR_PSKEY_UART_SEQ_TIMEOUT:
+ return "UART: BCSP ack timeout";
+ case CSR_PSKEY_UART_SEQ_RETRIES:
+ return "UART: retry limit in sequencing layer";
+ case CSR_PSKEY_UART_SEQ_WINSIZE:
+ return "UART: BCSP transmit window size";
+ case CSR_PSKEY_UART_USE_CRC_ON_TX:
+ return "UART: use BCSP CRCs";
+ case CSR_PSKEY_UART_HOST_INITIAL_STATE:
+ return "UART: initial host state";
+ case CSR_PSKEY_UART_HOST_ATTENTION_SPAN:
+ return "UART: host attention span";
+ case CSR_PSKEY_UART_HOST_WAKEUP_TIME:
+ return "UART: host wakeup time";
+ case CSR_PSKEY_UART_HOST_WAKEUP_WAIT:
+ return "UART: host wakeup wait";
+ case CSR_PSKEY_BCSP_LM_MODE:
+ return "BCSP link establishment mode";
+ case CSR_PSKEY_BCSP_LM_SYNC_RETRIES:
+ return "BCSP link establishment sync retries";
+ case CSR_PSKEY_BCSP_LM_TSHY:
+ return "BCSP link establishment Tshy";
+ case CSR_PSKEY_UART_DFU_CONFIG_STOP_BITS:
+ return "DFU mode UART: stop bits";
+ case CSR_PSKEY_UART_DFU_CONFIG_PARITY_BIT:
+ return "DFU mode UART: parity bit";
+ case CSR_PSKEY_UART_DFU_CONFIG_FLOW_CTRL_EN:
+ return "DFU mode UART: hardware flow control";
+ case CSR_PSKEY_UART_DFU_CONFIG_RTS_AUTO_EN:
+ return "DFU mode UART: RTS auto-enabled";
+ case CSR_PSKEY_UART_DFU_CONFIG_RTS:
+ return "DFU mode UART: RTS asserted";
+ case CSR_PSKEY_UART_DFU_CONFIG_TX_ZERO_EN:
+ return "DFU mode UART: TX zero enable";
+ case CSR_PSKEY_UART_DFU_CONFIG_NON_BCSP_EN:
+ return "DFU mode UART: enable BCSP-specific hardware";
+ case CSR_PSKEY_UART_DFU_CONFIG_RX_RATE_DELAY:
+ return "DFU mode UART: RX rate delay";
+ case CSR_PSKEY_AMUX_AIO0:
+ return "Multiplexer for AIO 0";
+ case CSR_PSKEY_AMUX_AIO1:
+ return "Multiplexer for AIO 1";
+ case CSR_PSKEY_AMUX_AIO2:
+ return "Multiplexer for AIO 2";
+ case CSR_PSKEY_AMUX_AIO3:
+ return "Multiplexer for AIO 3";
+ case CSR_PSKEY_LOCAL_NAME_SIMPLIFIED:
+ return "Local Name (simplified)";
+ case CSR_PSKEY_EXTENDED_STUB:
+ return "Extended stub";
+ default:
+ return "Unknown";
+ }
+}
+
+char *csr_pskeytoval(uint16_t pskey)
+{
+ switch (pskey) {
+ case CSR_PSKEY_BDADDR:
+ return "BDADDR";
+ case CSR_PSKEY_COUNTRYCODE:
+ return "COUNTRYCODE";
+ case CSR_PSKEY_CLASSOFDEVICE:
+ return "CLASSOFDEVICE";
+ case CSR_PSKEY_DEVICE_DRIFT:
+ return "DEVICE_DRIFT";
+ case CSR_PSKEY_DEVICE_JITTER:
+ return "DEVICE_JITTER";
+ case CSR_PSKEY_MAX_ACLS:
+ return "MAX_ACLS";
+ case CSR_PSKEY_MAX_SCOS:
+ return "MAX_SCOS";
+ case CSR_PSKEY_MAX_REMOTE_MASTERS:
+ return "MAX_REMOTE_MASTERS";
+ case CSR_PSKEY_ENABLE_MASTERY_WITH_SLAVERY:
+ return "ENABLE_MASTERY_WITH_SLAVERY";
+ case CSR_PSKEY_H_HC_FC_MAX_ACL_PKT_LEN:
+ return "H_HC_FC_MAX_ACL_PKT_LEN";
+ case CSR_PSKEY_H_HC_FC_MAX_SCO_PKT_LEN:
+ return "H_HC_FC_MAX_SCO_PKT_LEN";
+ case CSR_PSKEY_H_HC_FC_MAX_ACL_PKTS:
+ return "H_HC_FC_MAX_ACL_PKTS";
+ case CSR_PSKEY_H_HC_FC_MAX_SCO_PKTS:
+ return "H_HC_FC_MAX_SCO_PKTS";
+ case CSR_PSKEY_LC_FC_BUFFER_LOW_WATER_MARK:
+ return "LC_FC_BUFFER_LOW_WATER_MARK";
+ case CSR_PSKEY_LC_MAX_TX_POWER:
+ return "LC_MAX_TX_POWER";
+ case CSR_PSKEY_TX_GAIN_RAMP:
+ return "TX_GAIN_RAMP";
+ case CSR_PSKEY_LC_POWER_TABLE:
+ return "LC_POWER_TABLE";
+ case CSR_PSKEY_LC_PEER_POWER_PERIOD:
+ return "LC_PEER_POWER_PERIOD";
+ case CSR_PSKEY_LC_FC_POOLS_LOW_WATER_MARK:
+ return "LC_FC_POOLS_LOW_WATER_MARK";
+ case CSR_PSKEY_LC_DEFAULT_TX_POWER:
+ return "LC_DEFAULT_TX_POWER";
+ case CSR_PSKEY_LC_RSSI_GOLDEN_RANGE:
+ return "LC_RSSI_GOLDEN_RANGE";
+ case CSR_PSKEY_LC_COMBO_DISABLE_PIO_MASK:
+ return "LC_COMBO_DISABLE_PIO_MASK";
+ case CSR_PSKEY_LC_COMBO_PRIORITY_PIO_MASK:
+ return "LC_COMBO_PRIORITY_PIO_MASK";
+ case CSR_PSKEY_LC_COMBO_DOT11_CHANNEL_PIO_BASE:
+ return "LC_COMBO_DOT11_CHANNEL_PIO_BASE";
+ case CSR_PSKEY_LC_COMBO_DOT11_BLOCK_CHANNELS:
+ return "LC_COMBO_DOT11_BLOCK_CHANNELS";
+ case CSR_PSKEY_LC_MAX_TX_POWER_NO_RSSI:
+ return "LC_MAX_TX_POWER_NO_RSSI";
+ case CSR_PSKEY_LC_CONNECTION_RX_WINDOW:
+ return "LC_CONNECTION_RX_WINDOW";
+ case CSR_PSKEY_LC_COMBO_DOT11_TX_PROTECTION_MODE:
+ return "LC_COMBO_DOT11_TX_PROTECTION_MODE";
+ case CSR_PSKEY_LC_ENHANCED_POWER_TABLE:
+ return "LC_ENHANCED_POWER_TABLE";
+ case CSR_PSKEY_LC_WIDEBAND_RSSI_CONFIG:
+ return "LC_WIDEBAND_RSSI_CONFIG";
+ case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_LEAD:
+ return "LC_COMBO_DOT11_PRIORITY_LEAD";
+ case CSR_PSKEY_BT_CLOCK_INIT:
+ return "BT_CLOCK_INIT";
+ case CSR_PSKEY_TX_MR_MOD_DELAY:
+ return "TX_MR_MOD_DELAY";
+ case CSR_PSKEY_RX_MR_SYNC_TIMING:
+ return "RX_MR_SYNC_TIMING";
+ case CSR_PSKEY_RX_MR_SYNC_CONFIG:
+ return "RX_MR_SYNC_CONFIG";
+ case CSR_PSKEY_LC_LOST_SYNC_SLOTS:
+ return "LC_LOST_SYNC_SLOTS";
+ case CSR_PSKEY_RX_MR_SAMP_CONFIG:
+ return "RX_MR_SAMP_CONFIG";
+ case CSR_PSKEY_AGC_HYST_LEVELS:
+ return "AGC_HYST_LEVELS";
+ case CSR_PSKEY_RX_LEVEL_LOW_SIGNAL:
+ return "RX_LEVEL_LOW_SIGNAL";
+ case CSR_PSKEY_AGC_IQ_LVL_VALUES:
+ return "AGC_IQ_LVL_VALUES";
+ case CSR_PSKEY_MR_FTRIM_OFFSET_12DB:
+ return "MR_FTRIM_OFFSET_12DB";
+ case CSR_PSKEY_MR_FTRIM_OFFSET_6DB:
+ return "MR_FTRIM_OFFSET_6DB";
+ case CSR_PSKEY_NO_CAL_ON_BOOT:
+ return "NO_CAL_ON_BOOT";
+ case CSR_PSKEY_RSSI_HI_TARGET:
+ return "RSSI_HI_TARGET";
+ case CSR_PSKEY_PREFERRED_MIN_ATTENUATION:
+ return "PREFERRED_MIN_ATTENUATION";
+ case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_OVERRIDE:
+ return "LC_COMBO_DOT11_PRIORITY_OVERRIDE";
+ case CSR_PSKEY_LC_MULTISLOT_HOLDOFF:
+ return "LC_MULTISLOT_HOLDOFF";
+ case CSR_PSKEY_FREE_KEY_PIGEON_HOLE:
+ return "FREE_KEY_PIGEON_HOLE";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR0:
+ return "LINK_KEY_BD_ADDR0";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR1:
+ return "LINK_KEY_BD_ADDR1";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR2:
+ return "LINK_KEY_BD_ADDR2";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR3:
+ return "LINK_KEY_BD_ADDR3";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR4:
+ return "LINK_KEY_BD_ADDR4";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR5:
+ return "LINK_KEY_BD_ADDR5";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR6:
+ return "LINK_KEY_BD_ADDR6";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR7:
+ return "LINK_KEY_BD_ADDR7";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR8:
+ return "LINK_KEY_BD_ADDR8";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR9:
+ return "LINK_KEY_BD_ADDR9";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR10:
+ return "LINK_KEY_BD_ADDR10";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR11:
+ return "LINK_KEY_BD_ADDR11";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR12:
+ return "LINK_KEY_BD_ADDR12";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR13:
+ return "LINK_KEY_BD_ADDR13";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR14:
+ return "LINK_KEY_BD_ADDR14";
+ case CSR_PSKEY_LINK_KEY_BD_ADDR15:
+ return "LINK_KEY_BD_ADDR15";
+ case CSR_PSKEY_ENC_KEY_LMIN:
+ return "ENC_KEY_LMIN";
+ case CSR_PSKEY_ENC_KEY_LMAX:
+ return "ENC_KEY_LMAX";
+ case CSR_PSKEY_LOCAL_SUPPORTED_FEATURES:
+ return "LOCAL_SUPPORTED_FEATURES";
+ case CSR_PSKEY_LM_USE_UNIT_KEY:
+ return "LM_USE_UNIT_KEY";
+ case CSR_PSKEY_HCI_NOP_DISABLE:
+ return "HCI_NOP_DISABLE";
+ case CSR_PSKEY_LM_MAX_EVENT_FILTERS:
+ return "LM_MAX_EVENT_FILTERS";
+ case CSR_PSKEY_LM_USE_ENC_MODE_BROADCAST:
+ return "LM_USE_ENC_MODE_BROADCAST";
+ case CSR_PSKEY_LM_TEST_SEND_ACCEPTED_TWICE:
+ return "LM_TEST_SEND_ACCEPTED_TWICE";
+ case CSR_PSKEY_LM_MAX_PAGE_HOLD_TIME:
+ return "LM_MAX_PAGE_HOLD_TIME";
+ case CSR_PSKEY_AFH_ADAPTATION_RESPONSE_TIME:
+ return "AFH_ADAPTATION_RESPONSE_TIME";
+ case CSR_PSKEY_AFH_OPTIONS:
+ return "AFH_OPTIONS";
+ case CSR_PSKEY_AFH_RSSI_RUN_PERIOD:
+ return "AFH_RSSI_RUN_PERIOD";
+ case CSR_PSKEY_AFH_REENABLE_CHANNEL_TIME:
+ return "AFH_REENABLE_CHANNEL_TIME";
+ case CSR_PSKEY_NO_DROP_ON_ACR_MS_FAIL:
+ return "NO_DROP_ON_ACR_MS_FAIL";
+ case CSR_PSKEY_MAX_PRIVATE_KEYS:
+ return "MAX_PRIVATE_KEYS";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR0:
+ return "PRIVATE_LINK_KEY_BD_ADDR0";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR1:
+ return "PRIVATE_LINK_KEY_BD_ADDR1";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR2:
+ return "PRIVATE_LINK_KEY_BD_ADDR2";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR3:
+ return "PRIVATE_LINK_KEY_BD_ADDR3";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR4:
+ return "PRIVATE_LINK_KEY_BD_ADDR4";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR5:
+ return "PRIVATE_LINK_KEY_BD_ADDR5";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR6:
+ return "PRIVATE_LINK_KEY_BD_ADDR6";
+ case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR7:
+ return "PRIVATE_LINK_KEY_BD_ADDR7";
+ case CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS:
+ return "LOCAL_SUPPORTED_COMMANDS";
+ case CSR_PSKEY_LM_MAX_ABSENCE_INDEX:
+ return "LM_MAX_ABSENCE_INDEX";
+ case CSR_PSKEY_DEVICE_NAME:
+ return "DEVICE_NAME";
+ case CSR_PSKEY_AFH_RSSI_THRESHOLD:
+ return "AFH_RSSI_THRESHOLD";
+ case CSR_PSKEY_LM_CASUAL_SCAN_INTERVAL:
+ return "LM_CASUAL_SCAN_INTERVAL";
+ case CSR_PSKEY_AFH_MIN_MAP_CHANGE:
+ return "AFH_MIN_MAP_CHANGE";
+ case CSR_PSKEY_AFH_RSSI_LP_RUN_PERIOD:
+ return "AFH_RSSI_LP_RUN_PERIOD";
+ case CSR_PSKEY_HCI_LMP_LOCAL_VERSION:
+ return "HCI_LMP_LOCAL_VERSION";
+ case CSR_PSKEY_LMP_REMOTE_VERSION:
+ return "LMP_REMOTE_VERSION";
+ case CSR_PSKEY_HOLD_ERROR_MESSAGE_NUMBER:
+ return "HOLD_ERROR_MESSAGE_NUMBER";
+ case CSR_PSKEY_DFU_ATTRIBUTES:
+ return "DFU_ATTRIBUTES";
+ case CSR_PSKEY_DFU_DETACH_TO:
+ return "DFU_DETACH_TO";
+ case CSR_PSKEY_DFU_TRANSFER_SIZE:
+ return "DFU_TRANSFER_SIZE";
+ case CSR_PSKEY_DFU_ENABLE:
+ return "DFU_ENABLE";
+ case CSR_PSKEY_DFU_LIN_REG_ENABLE:
+ return "DFU_LIN_REG_ENABLE";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_MSB:
+ return "DFUENC_VMAPP_PK_MODULUS_MSB";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_LSB:
+ return "DFUENC_VMAPP_PK_MODULUS_LSB";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_M_DASH:
+ return "DFUENC_VMAPP_PK_M_DASH";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_MSB:
+ return "DFUENC_VMAPP_PK_R2N_MSB";
+ case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_LSB:
+ return "DFUENC_VMAPP_PK_R2N_LSB";
+ case CSR_PSKEY_BCSP_LM_PS_BLOCK:
+ return "BCSP_LM_PS_BLOCK";
+ case CSR_PSKEY_HOSTIO_FC_PS_BLOCK:
+ return "HOSTIO_FC_PS_BLOCK";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO0:
+ return "HOSTIO_PROTOCOL_INFO0";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO1:
+ return "HOSTIO_PROTOCOL_INFO1";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO2:
+ return "HOSTIO_PROTOCOL_INFO2";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO3:
+ return "HOSTIO_PROTOCOL_INFO3";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO4:
+ return "HOSTIO_PROTOCOL_INFO4";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO5:
+ return "HOSTIO_PROTOCOL_INFO5";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO6:
+ return "HOSTIO_PROTOCOL_INFO6";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO7:
+ return "HOSTIO_PROTOCOL_INFO7";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO8:
+ return "HOSTIO_PROTOCOL_INFO8";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO9:
+ return "HOSTIO_PROTOCOL_INFO9";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO10:
+ return "HOSTIO_PROTOCOL_INFO10";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO11:
+ return "HOSTIO_PROTOCOL_INFO11";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO12:
+ return "HOSTIO_PROTOCOL_INFO12";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO13:
+ return "HOSTIO_PROTOCOL_INFO13";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO14:
+ return "HOSTIO_PROTOCOL_INFO14";
+ case CSR_PSKEY_HOSTIO_PROTOCOL_INFO15:
+ return "HOSTIO_PROTOCOL_INFO15";
+ case CSR_PSKEY_HOSTIO_UART_RESET_TIMEOUT:
+ return "HOSTIO_UART_RESET_TIMEOUT";
+ case CSR_PSKEY_HOSTIO_USE_HCI_EXTN:
+ return "HOSTIO_USE_HCI_EXTN";
+ case CSR_PSKEY_HOSTIO_USE_HCI_EXTN_CCFC:
+ return "HOSTIO_USE_HCI_EXTN_CCFC";
+ case CSR_PSKEY_HOSTIO_HCI_EXTN_PAYLOAD_SIZE:
+ return "HOSTIO_HCI_EXTN_PAYLOAD_SIZE";
+ case CSR_PSKEY_BCSP_LM_CNF_CNT_LIMIT:
+ return "BCSP_LM_CNF_CNT_LIMIT";
+ case CSR_PSKEY_HOSTIO_MAP_SCO_PCM:
+ return "HOSTIO_MAP_SCO_PCM";
+ case CSR_PSKEY_HOSTIO_AWKWARD_PCM_SYNC:
+ return "HOSTIO_AWKWARD_PCM_SYNC";
+ case CSR_PSKEY_HOSTIO_BREAK_POLL_PERIOD:
+ return "HOSTIO_BREAK_POLL_PERIOD";
+ case CSR_PSKEY_HOSTIO_MIN_UART_HCI_SCO_SIZE:
+ return "HOSTIO_MIN_UART_HCI_SCO_SIZE";
+ case CSR_PSKEY_HOSTIO_MAP_SCO_CODEC:
+ return "HOSTIO_MAP_SCO_CODEC";
+ case CSR_PSKEY_PCM_CVSD_TX_HI_FREQ_BOOST:
+ return "PCM_CVSD_TX_HI_FREQ_BOOST";
+ case CSR_PSKEY_PCM_CVSD_RX_HI_FREQ_BOOST:
+ return "PCM_CVSD_RX_HI_FREQ_BOOST";
+ case CSR_PSKEY_PCM_CONFIG32:
+ return "PCM_CONFIG32";
+ case CSR_PSKEY_USE_OLD_BCSP_LE:
+ return "USE_OLD_BCSP_LE";
+ case CSR_PSKEY_PCM_CVSD_USE_NEW_FILTER:
+ return "PCM_CVSD_USE_NEW_FILTER";
+ case CSR_PSKEY_PCM_FORMAT:
+ return "PCM_FORMAT";
+ case CSR_PSKEY_CODEC_OUT_GAIN:
+ return "CODEC_OUT_GAIN";
+ case CSR_PSKEY_CODEC_IN_GAIN:
+ return "CODEC_IN_GAIN";
+ case CSR_PSKEY_CODEC_PIO:
+ return "CODEC_PIO";
+ case CSR_PSKEY_PCM_LOW_JITTER_CONFIG:
+ return "PCM_LOW_JITTER_CONFIG";
+ case CSR_PSKEY_HOSTIO_SCO_PCM_THRESHOLDS:
+ return "HOSTIO_SCO_PCM_THRESHOLDS";
+ case CSR_PSKEY_HOSTIO_SCO_HCI_THRESHOLDS:
+ return "HOSTIO_SCO_HCI_THRESHOLDS";
+ case CSR_PSKEY_HOSTIO_MAP_SCO_PCM_SLOT:
+ return "HOSTIO_MAP_SCO_PCM_SLOT";
+ case CSR_PSKEY_UART_BAUDRATE:
+ return "UART_BAUDRATE";
+ case CSR_PSKEY_UART_CONFIG_BCSP:
+ return "UART_CONFIG_BCSP";
+ case CSR_PSKEY_UART_CONFIG_H4:
+ return "UART_CONFIG_H4";
+ case CSR_PSKEY_UART_CONFIG_H5:
+ return "UART_CONFIG_H5";
+ case CSR_PSKEY_UART_CONFIG_USR:
+ return "UART_CONFIG_USR";
+ case CSR_PSKEY_UART_TX_CRCS:
+ return "UART_TX_CRCS";
+ case CSR_PSKEY_UART_ACK_TIMEOUT:
+ return "UART_ACK_TIMEOUT";
+ case CSR_PSKEY_UART_TX_MAX_ATTEMPTS:
+ return "UART_TX_MAX_ATTEMPTS";
+ case CSR_PSKEY_UART_TX_WINDOW_SIZE:
+ return "UART_TX_WINDOW_SIZE";
+ case CSR_PSKEY_UART_HOST_WAKE:
+ return "UART_HOST_WAKE";
+ case CSR_PSKEY_HOSTIO_THROTTLE_TIMEOUT:
+ return "HOSTIO_THROTTLE_TIMEOUT";
+ case CSR_PSKEY_PCM_ALWAYS_ENABLE:
+ return "PCM_ALWAYS_ENABLE";
+ case CSR_PSKEY_UART_HOST_WAKE_SIGNAL:
+ return "UART_HOST_WAKE_SIGNAL";
+ case CSR_PSKEY_UART_CONFIG_H4DS:
+ return "UART_CONFIG_H4DS";
+ case CSR_PSKEY_H4DS_WAKE_DURATION:
+ return "H4DS_WAKE_DURATION";
+ case CSR_PSKEY_H4DS_MAXWU:
+ return "H4DS_MAXWU";
+ case CSR_PSKEY_H4DS_LE_TIMER_PERIOD:
+ return "H4DS_LE_TIMER_PERIOD";
+ case CSR_PSKEY_H4DS_TWU_TIMER_PERIOD:
+ return "H4DS_TWU_TIMER_PERIOD";
+ case CSR_PSKEY_H4DS_UART_IDLE_TIMER_PERIOD:
+ return "H4DS_UART_IDLE_TIMER_PERIOD";
+ case CSR_PSKEY_ANA_FTRIM:
+ return "ANA_FTRIM";
+ case CSR_PSKEY_WD_TIMEOUT:
+ return "WD_TIMEOUT";
+ case CSR_PSKEY_WD_PERIOD:
+ return "WD_PERIOD";
+ case CSR_PSKEY_HOST_INTERFACE:
+ return "HOST_INTERFACE";
+ case CSR_PSKEY_HQ_HOST_TIMEOUT:
+ return "HQ_HOST_TIMEOUT";
+ case CSR_PSKEY_HQ_ACTIVE:
+ return "HQ_ACTIVE";
+ case CSR_PSKEY_BCCMD_SECURITY_ACTIVE:
+ return "BCCMD_SECURITY_ACTIVE";
+ case CSR_PSKEY_ANA_FREQ:
+ return "ANA_FREQ";
+ case CSR_PSKEY_PIO_PROTECT_MASK:
+ return "PIO_PROTECT_MASK";
+ case CSR_PSKEY_PMALLOC_SIZES:
+ return "PMALLOC_SIZES";
+ case CSR_PSKEY_UART_BAUD_RATE:
+ return "UART_BAUD_RATE";
+ case CSR_PSKEY_UART_CONFIG:
+ return "UART_CONFIG";
+ case CSR_PSKEY_STUB:
+ return "STUB";
+ case CSR_PSKEY_TXRX_PIO_CONTROL:
+ return "TXRX_PIO_CONTROL";
+ case CSR_PSKEY_ANA_RX_LEVEL:
+ return "ANA_RX_LEVEL";
+ case CSR_PSKEY_ANA_RX_FTRIM:
+ return "ANA_RX_FTRIM";
+ case CSR_PSKEY_PSBC_DATA_VERSION:
+ return "PSBC_DATA_VERSION";
+ case CSR_PSKEY_PCM0_ATTENUATION:
+ return "PCM0_ATTENUATION";
+ case CSR_PSKEY_LO_LVL_MAX:
+ return "LO_LVL_MAX";
+ case CSR_PSKEY_LO_ADC_AMPL_MIN:
+ return "LO_ADC_AMPL_MIN";
+ case CSR_PSKEY_LO_ADC_AMPL_MAX:
+ return "LO_ADC_AMPL_MAX";
+ case CSR_PSKEY_IQ_TRIM_CHANNEL:
+ return "IQ_TRIM_CHANNEL";
+ case CSR_PSKEY_IQ_TRIM_GAIN:
+ return "IQ_TRIM_GAIN";
+ case CSR_PSKEY_IQ_TRIM_ENABLE:
+ return "IQ_TRIM_ENABLE";
+ case CSR_PSKEY_TX_OFFSET_HALF_MHZ:
+ return "TX_OFFSET_HALF_MHZ";
+ case CSR_PSKEY_GBL_MISC_ENABLES:
+ return "GBL_MISC_ENABLES";
+ case CSR_PSKEY_UART_SLEEP_TIMEOUT:
+ return "UART_SLEEP_TIMEOUT";
+ case CSR_PSKEY_DEEP_SLEEP_STATE:
+ return "DEEP_SLEEP_STATE";
+ case CSR_PSKEY_IQ_ENABLE_PHASE_TRIM:
+ return "IQ_ENABLE_PHASE_TRIM";
+ case CSR_PSKEY_HCI_HANDLE_FREEZE_PERIOD:
+ return "HCI_HANDLE_FREEZE_PERIOD";
+ case CSR_PSKEY_MAX_FROZEN_HCI_HANDLES:
+ return "MAX_FROZEN_HCI_HANDLES";
+ case CSR_PSKEY_PAGETABLE_DESTRUCTION_DELAY:
+ return "PAGETABLE_DESTRUCTION_DELAY";
+ case CSR_PSKEY_IQ_TRIM_PIO_SETTINGS:
+ return "IQ_TRIM_PIO_SETTINGS";
+ case CSR_PSKEY_USE_EXTERNAL_CLOCK:
+ return "USE_EXTERNAL_CLOCK";
+ case CSR_PSKEY_DEEP_SLEEP_WAKE_CTS:
+ return "DEEP_SLEEP_WAKE_CTS";
+ case CSR_PSKEY_FC_HC2H_FLUSH_DELAY:
+ return "FC_HC2H_FLUSH_DELAY";
+ case CSR_PSKEY_RX_HIGHSIDE:
+ return "RX_HIGHSIDE";
+ case CSR_PSKEY_TX_PRE_LVL:
+ return "TX_PRE_LVL";
+ case CSR_PSKEY_RX_SINGLE_ENDED:
+ return "RX_SINGLE_ENDED";
+ case CSR_PSKEY_TX_FILTER_CONFIG:
+ return "TX_FILTER_CONFIG";
+ case CSR_PSKEY_CLOCK_REQUEST_ENABLE:
+ return "CLOCK_REQUEST_ENABLE";
+ case CSR_PSKEY_RX_MIN_ATTEN:
+ return "RX_MIN_ATTEN";
+ case CSR_PSKEY_XTAL_TARGET_AMPLITUDE:
+ return "XTAL_TARGET_AMPLITUDE";
+ case CSR_PSKEY_PCM_MIN_CPU_CLOCK:
+ return "PCM_MIN_CPU_CLOCK";
+ case CSR_PSKEY_HOST_INTERFACE_PIO_USB:
+ return "HOST_INTERFACE_PIO_USB";
+ case CSR_PSKEY_CPU_IDLE_MODE:
+ return "CPU_IDLE_MODE";
+ case CSR_PSKEY_DEEP_SLEEP_CLEAR_RTS:
+ return "DEEP_SLEEP_CLEAR_RTS";
+ case CSR_PSKEY_RF_RESONANCE_TRIM:
+ return "RF_RESONANCE_TRIM";
+ case CSR_PSKEY_DEEP_SLEEP_PIO_WAKE:
+ return "DEEP_SLEEP_PIO_WAKE";
+ case CSR_PSKEY_DRAIN_BORE_TIMERS:
+ return "DRAIN_BORE_TIMERS";
+ case CSR_PSKEY_DRAIN_TX_POWER_BASE:
+ return "DRAIN_TX_POWER_BASE";
+ case CSR_PSKEY_MODULE_ID:
+ return "MODULE_ID";
+ case CSR_PSKEY_MODULE_DESIGN:
+ return "MODULE_DESIGN";
+ case CSR_PSKEY_MODULE_SECURITY_CODE:
+ return "MODULE_SECURITY_CODE";
+ case CSR_PSKEY_VM_DISABLE:
+ return "VM_DISABLE";
+ case CSR_PSKEY_MOD_MANUF0:
+ return "MOD_MANUF0";
+ case CSR_PSKEY_MOD_MANUF1:
+ return "MOD_MANUF1";
+ case CSR_PSKEY_MOD_MANUF2:
+ return "MOD_MANUF2";
+ case CSR_PSKEY_MOD_MANUF3:
+ return "MOD_MANUF3";
+ case CSR_PSKEY_MOD_MANUF4:
+ return "MOD_MANUF4";
+ case CSR_PSKEY_MOD_MANUF5:
+ return "MOD_MANUF5";
+ case CSR_PSKEY_MOD_MANUF6:
+ return "MOD_MANUF6";
+ case CSR_PSKEY_MOD_MANUF7:
+ return "MOD_MANUF7";
+ case CSR_PSKEY_MOD_MANUF8:
+ return "MOD_MANUF8";
+ case CSR_PSKEY_MOD_MANUF9:
+ return "MOD_MANUF9";
+ case CSR_PSKEY_DUT_VM_DISABLE:
+ return "DUT_VM_DISABLE";
+ case CSR_PSKEY_USR0:
+ return "USR0";
+ case CSR_PSKEY_USR1:
+ return "USR1";
+ case CSR_PSKEY_USR2:
+ return "USR2";
+ case CSR_PSKEY_USR3:
+ return "USR3";
+ case CSR_PSKEY_USR4:
+ return "USR4";
+ case CSR_PSKEY_USR5:
+ return "USR5";
+ case CSR_PSKEY_USR6:
+ return "USR6";
+ case CSR_PSKEY_USR7:
+ return "USR7";
+ case CSR_PSKEY_USR8:
+ return "USR8";
+ case CSR_PSKEY_USR9:
+ return "USR9";
+ case CSR_PSKEY_USR10:
+ return "USR10";
+ case CSR_PSKEY_USR11:
+ return "USR11";
+ case CSR_PSKEY_USR12:
+ return "USR12";
+ case CSR_PSKEY_USR13:
+ return "USR13";
+ case CSR_PSKEY_USR14:
+ return "USR14";
+ case CSR_PSKEY_USR15:
+ return "USR15";
+ case CSR_PSKEY_USR16:
+ return "USR16";
+ case CSR_PSKEY_USR17:
+ return "USR17";
+ case CSR_PSKEY_USR18:
+ return "USR18";
+ case CSR_PSKEY_USR19:
+ return "USR19";
+ case CSR_PSKEY_USR20:
+ return "USR20";
+ case CSR_PSKEY_USR21:
+ return "USR21";
+ case CSR_PSKEY_USR22:
+ return "USR22";
+ case CSR_PSKEY_USR23:
+ return "USR23";
+ case CSR_PSKEY_USR24:
+ return "USR24";
+ case CSR_PSKEY_USR25:
+ return "USR25";
+ case CSR_PSKEY_USR26:
+ return "USR26";
+ case CSR_PSKEY_USR27:
+ return "USR27";
+ case CSR_PSKEY_USR28:
+ return "USR28";
+ case CSR_PSKEY_USR29:
+ return "USR29";
+ case CSR_PSKEY_USR30:
+ return "USR30";
+ case CSR_PSKEY_USR31:
+ return "USR31";
+ case CSR_PSKEY_USR32:
+ return "USR32";
+ case CSR_PSKEY_USR33:
+ return "USR33";
+ case CSR_PSKEY_USR34:
+ return "USR34";
+ case CSR_PSKEY_USR35:
+ return "USR35";
+ case CSR_PSKEY_USR36:
+ return "USR36";
+ case CSR_PSKEY_USR37:
+ return "USR37";
+ case CSR_PSKEY_USR38:
+ return "USR38";
+ case CSR_PSKEY_USR39:
+ return "USR39";
+ case CSR_PSKEY_USR40:
+ return "USR40";
+ case CSR_PSKEY_USR41:
+ return "USR41";
+ case CSR_PSKEY_USR42:
+ return "USR42";
+ case CSR_PSKEY_USR43:
+ return "USR43";
+ case CSR_PSKEY_USR44:
+ return "USR44";
+ case CSR_PSKEY_USR45:
+ return "USR45";
+ case CSR_PSKEY_USR46:
+ return "USR46";
+ case CSR_PSKEY_USR47:
+ return "USR47";
+ case CSR_PSKEY_USR48:
+ return "USR48";
+ case CSR_PSKEY_USR49:
+ return "USR49";
+ case CSR_PSKEY_USB_VERSION:
+ return "USB_VERSION";
+ case CSR_PSKEY_USB_DEVICE_CLASS_CODES:
+ return "USB_DEVICE_CLASS_CODES";
+ case CSR_PSKEY_USB_VENDOR_ID:
+ return "USB_VENDOR_ID";
+ case CSR_PSKEY_USB_PRODUCT_ID:
+ return "USB_PRODUCT_ID";
+ case CSR_PSKEY_USB_MANUF_STRING:
+ return "USB_MANUF_STRING";
+ case CSR_PSKEY_USB_PRODUCT_STRING:
+ return "USB_PRODUCT_STRING";
+ case CSR_PSKEY_USB_SERIAL_NUMBER_STRING:
+ return "USB_SERIAL_NUMBER_STRING";
+ case CSR_PSKEY_USB_CONFIG_STRING:
+ return "USB_CONFIG_STRING";
+ case CSR_PSKEY_USB_ATTRIBUTES:
+ return "USB_ATTRIBUTES";
+ case CSR_PSKEY_USB_MAX_POWER:
+ return "USB_MAX_POWER";
+ case CSR_PSKEY_USB_BT_IF_CLASS_CODES:
+ return "USB_BT_IF_CLASS_CODES";
+ case CSR_PSKEY_USB_LANGID:
+ return "USB_LANGID";
+ case CSR_PSKEY_USB_DFU_CLASS_CODES:
+ return "USB_DFU_CLASS_CODES";
+ case CSR_PSKEY_USB_DFU_PRODUCT_ID:
+ return "USB_DFU_PRODUCT_ID";
+ case CSR_PSKEY_USB_PIO_DETACH:
+ return "USB_PIO_DETACH";
+ case CSR_PSKEY_USB_PIO_WAKEUP:
+ return "USB_PIO_WAKEUP";
+ case CSR_PSKEY_USB_PIO_PULLUP:
+ return "USB_PIO_PULLUP";
+ case CSR_PSKEY_USB_PIO_VBUS:
+ return "USB_PIO_VBUS";
+ case CSR_PSKEY_USB_PIO_WAKE_TIMEOUT:
+ return "USB_PIO_WAKE_TIMEOUT";
+ case CSR_PSKEY_USB_PIO_RESUME:
+ return "USB_PIO_RESUME";
+ case CSR_PSKEY_USB_BT_SCO_IF_CLASS_CODES:
+ return "USB_BT_SCO_IF_CLASS_CODES";
+ case CSR_PSKEY_USB_SUSPEND_PIO_LEVEL:
+ return "USB_SUSPEND_PIO_LEVEL";
+ case CSR_PSKEY_USB_SUSPEND_PIO_DIR:
+ return "USB_SUSPEND_PIO_DIR";
+ case CSR_PSKEY_USB_SUSPEND_PIO_MASK:
+ return "USB_SUSPEND_PIO_MASK";
+ case CSR_PSKEY_USB_ENDPOINT_0_MAX_PACKET_SIZE:
+ return "USB_ENDPOINT_0_MAX_PACKET_SIZE";
+ case CSR_PSKEY_USB_CONFIG:
+ return "USB_CONFIG";
+ case CSR_PSKEY_RADIOTEST_ATTEN_INIT:
+ return "RADIOTEST_ATTEN_INIT";
+ case CSR_PSKEY_RADIOTEST_FIRST_TRIM_TIME:
+ return "RADIOTEST_FIRST_TRIM_TIME";
+ case CSR_PSKEY_RADIOTEST_SUBSEQUENT_TRIM_TIME:
+ return "RADIOTEST_SUBSEQUENT_TRIM_TIME";
+ case CSR_PSKEY_RADIOTEST_LO_LVL_TRIM_ENABLE:
+ return "RADIOTEST_LO_LVL_TRIM_ENABLE";
+ case CSR_PSKEY_RADIOTEST_DISABLE_MODULATION:
+ return "RADIOTEST_DISABLE_MODULATION";
+ case CSR_PSKEY_RFCOMM_FCON_THRESHOLD:
+ return "RFCOMM_FCON_THRESHOLD";
+ case CSR_PSKEY_RFCOMM_FCOFF_THRESHOLD:
+ return "RFCOMM_FCOFF_THRESHOLD";
+ case CSR_PSKEY_IPV6_STATIC_ADDR:
+ return "IPV6_STATIC_ADDR";
+ case CSR_PSKEY_IPV4_STATIC_ADDR:
+ return "IPV4_STATIC_ADDR";
+ case CSR_PSKEY_IPV6_STATIC_PREFIX_LEN:
+ return "IPV6_STATIC_PREFIX_LEN";
+ case CSR_PSKEY_IPV6_STATIC_ROUTER_ADDR:
+ return "IPV6_STATIC_ROUTER_ADDR";
+ case CSR_PSKEY_IPV4_STATIC_SUBNET_MASK:
+ return "IPV4_STATIC_SUBNET_MASK";
+ case CSR_PSKEY_IPV4_STATIC_ROUTER_ADDR:
+ return "IPV4_STATIC_ROUTER_ADDR";
+ case CSR_PSKEY_MDNS_NAME:
+ return "MDNS_NAME";
+ case CSR_PSKEY_FIXED_PIN:
+ return "FIXED_PIN";
+ case CSR_PSKEY_MDNS_PORT:
+ return "MDNS_PORT";
+ case CSR_PSKEY_MDNS_TTL:
+ return "MDNS_TTL";
+ case CSR_PSKEY_MDNS_IPV4_ADDR:
+ return "MDNS_IPV4_ADDR";
+ case CSR_PSKEY_ARP_CACHE_TIMEOUT:
+ return "ARP_CACHE_TIMEOUT";
+ case CSR_PSKEY_HFP_POWER_TABLE:
+ return "HFP_POWER_TABLE";
+ case CSR_PSKEY_DRAIN_BORE_TIMER_COUNTERS:
+ return "DRAIN_BORE_TIMER_COUNTERS";
+ case CSR_PSKEY_DRAIN_BORE_COUNTERS:
+ return "DRAIN_BORE_COUNTERS";
+ case CSR_PSKEY_LOOP_FILTER_TRIM:
+ return "LOOP_FILTER_TRIM";
+ case CSR_PSKEY_DRAIN_BORE_CURRENT_PEAK:
+ return "DRAIN_BORE_CURRENT_PEAK";
+ case CSR_PSKEY_VM_E2_CACHE_LIMIT:
+ return "VM_E2_CACHE_LIMIT";
+ case CSR_PSKEY_FORCE_16MHZ_REF_PIO:
+ return "FORCE_16MHZ_REF_PIO";
+ case CSR_PSKEY_CDMA_LO_REF_LIMITS:
+ return "CDMA_LO_REF_LIMITS";
+ case CSR_PSKEY_CDMA_LO_ERROR_LIMITS:
+ return "CDMA_LO_ERROR_LIMITS";
+ case CSR_PSKEY_CLOCK_STARTUP_DELAY:
+ return "CLOCK_STARTUP_DELAY";
+ case CSR_PSKEY_DEEP_SLEEP_CORRECTION_FACTOR:
+ return "DEEP_SLEEP_CORRECTION_FACTOR";
+ case CSR_PSKEY_TEMPERATURE_CALIBRATION:
+ return "TEMPERATURE_CALIBRATION";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA:
+ return "TEMPERATURE_VS_DELTA_INTERNAL_PA";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL:
+ return "TEMPERATURE_VS_DELTA_TX_PRE_LVL";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB:
+ return "TEMPERATURE_VS_DELTA_TX_BB";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_ANA_FTRIM:
+ return "TEMPERATURE_VS_DELTA_ANA_FTRIM";
+ case CSR_PSKEY_TEST_DELTA_OFFSET:
+ return "TEST_DELTA_OFFSET";
+ case CSR_PSKEY_RX_DYNAMIC_LVL_OFFSET:
+ return "RX_DYNAMIC_LVL_OFFSET";
+ case CSR_PSKEY_TEST_FORCE_OFFSET:
+ return "TEST_FORCE_OFFSET";
+ case CSR_PSKEY_RF_TRAP_BAD_DIVISION_RATIOS:
+ return "RF_TRAP_BAD_DIVISION_RATIOS";
+ case CSR_PSKEY_RADIOTEST_CDMA_LO_REF_LIMITS:
+ return "RADIOTEST_CDMA_LO_REF_LIMITS";
+ case CSR_PSKEY_INITIAL_BOOTMODE:
+ return "INITIAL_BOOTMODE";
+ case CSR_PSKEY_ONCHIP_HCI_CLIENT:
+ return "ONCHIP_HCI_CLIENT";
+ case CSR_PSKEY_RX_ATTEN_BACKOFF:
+ return "RX_ATTEN_BACKOFF";
+ case CSR_PSKEY_RX_ATTEN_UPDATE_RATE:
+ return "RX_ATTEN_UPDATE_RATE";
+ case CSR_PSKEY_SYNTH_TXRX_THRESHOLDS:
+ return "SYNTH_TXRX_THRESHOLDS";
+ case CSR_PSKEY_MIN_WAIT_STATES:
+ return "MIN_WAIT_STATES";
+ case CSR_PSKEY_RSSI_CORRECTION:
+ return "RSSI_CORRECTION";
+ case CSR_PSKEY_SCHED_THROTTLE_TIMEOUT:
+ return "SCHED_THROTTLE_TIMEOUT";
+ case CSR_PSKEY_DEEP_SLEEP_USE_EXTERNAL_CLOCK:
+ return "DEEP_SLEEP_USE_EXTERNAL_CLOCK";
+ case CSR_PSKEY_TRIM_RADIO_FILTERS:
+ return "TRIM_RADIO_FILTERS";
+ case CSR_PSKEY_TRANSMIT_OFFSET:
+ return "TRANSMIT_OFFSET";
+ case CSR_PSKEY_USB_VM_CONTROL:
+ return "USB_VM_CONTROL";
+ case CSR_PSKEY_MR_ANA_RX_FTRIM:
+ return "MR_ANA_RX_FTRIM";
+ case CSR_PSKEY_I2C_CONFIG:
+ return "I2C_CONFIG";
+ case CSR_PSKEY_IQ_LVL_RX:
+ return "IQ_LVL_RX";
+ case CSR_PSKEY_MR_TX_FILTER_CONFIG:
+ return "MR_TX_FILTER_CONFIG";
+ case CSR_PSKEY_MR_TX_CONFIG2:
+ return "MR_TX_CONFIG2";
+ case CSR_PSKEY_USB_DONT_RESET_BOOTMODE_ON_HOST_RESET:
+ return "USB_DONT_RESET_BOOTMODE_ON_HOST_RESET";
+ case CSR_PSKEY_LC_USE_THROTTLING:
+ return "LC_USE_THROTTLING";
+ case CSR_PSKEY_CHARGER_TRIM:
+ return "CHARGER_TRIM";
+ case CSR_PSKEY_CLOCK_REQUEST_FEATURES:
+ return "CLOCK_REQUEST_FEATURES";
+ case CSR_PSKEY_TRANSMIT_OFFSET_CLASS1:
+ return "TRANSMIT_OFFSET_CLASS1";
+ case CSR_PSKEY_TX_AVOID_PA_CLASS1_PIO:
+ return "TX_AVOID_PA_CLASS1_PIO";
+ case CSR_PSKEY_MR_PIO_CONFIG:
+ return "MR_PIO_CONFIG";
+ case CSR_PSKEY_UART_CONFIG2:
+ return "UART_CONFIG2";
+ case CSR_PSKEY_CLASS1_IQ_LVL:
+ return "CLASS1_IQ_LVL";
+ case CSR_PSKEY_CLASS1_TX_CONFIG2:
+ return "CLASS1_TX_CONFIG2";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1:
+ return "TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1:
+ return "TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR:
+ return "TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER:
+ return "TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER";
+ case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD:
+ return "TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD";
+ case CSR_PSKEY_RX_MR_EQ_TAPS:
+ return "RX_MR_EQ_TAPS";
+ case CSR_PSKEY_TX_PRE_LVL_CLASS1:
+ return "TX_PRE_LVL_CLASS1";
+ case CSR_PSKEY_ANALOGUE_ATTENUATOR:
+ return "ANALOGUE_ATTENUATOR";
+ case CSR_PSKEY_MR_RX_FILTER_TRIM:
+ return "MR_RX_FILTER_TRIM";
+ case CSR_PSKEY_MR_RX_FILTER_RESPONSE:
+ return "MR_RX_FILTER_RESPONSE";
+ case CSR_PSKEY_PIO_WAKEUP_STATE:
+ return "PIO_WAKEUP_STATE";
+ case CSR_PSKEY_MR_TX_IF_ATTEN_OFF_TEMP:
+ return "MR_TX_IF_ATTEN_OFF_TEMP";
+ case CSR_PSKEY_LO_DIV_LATCH_BYPASS:
+ return "LO_DIV_LATCH_BYPASS";
+ case CSR_PSKEY_LO_VCO_STANDBY:
+ return "LO_VCO_STANDBY";
+ case CSR_PSKEY_SLOW_CLOCK_FILTER_SHIFT:
+ return "SLOW_CLOCK_FILTER_SHIFT";
+ case CSR_PSKEY_SLOW_CLOCK_FILTER_DIVIDER:
+ return "SLOW_CLOCK_FILTER_DIVIDER";
+ case CSR_PSKEY_USB_ATTRIBUTES_POWER:
+ return "USB_ATTRIBUTES_POWER";
+ case CSR_PSKEY_USB_ATTRIBUTES_WAKEUP:
+ return "USB_ATTRIBUTES_WAKEUP";
+ case CSR_PSKEY_DFU_ATTRIBUTES_MANIFESTATION_TOLERANT:
+ return "DFU_ATTRIBUTES_MANIFESTATION_TOLERANT";
+ case CSR_PSKEY_DFU_ATTRIBUTES_CAN_UPLOAD:
+ return "DFU_ATTRIBUTES_CAN_UPLOAD";
+ case CSR_PSKEY_DFU_ATTRIBUTES_CAN_DOWNLOAD:
+ return "DFU_ATTRIBUTES_CAN_DOWNLOAD";
+ case CSR_PSKEY_UART_CONFIG_STOP_BITS:
+ return "UART_CONFIG_STOP_BITS";
+ case CSR_PSKEY_UART_CONFIG_PARITY_BIT:
+ return "UART_CONFIG_PARITY_BIT";
+ case CSR_PSKEY_UART_CONFIG_FLOW_CTRL_EN:
+ return "UART_CONFIG_FLOW_CTRL_EN";
+ case CSR_PSKEY_UART_CONFIG_RTS_AUTO_EN:
+ return "UART_CONFIG_RTS_AUTO_EN";
+ case CSR_PSKEY_UART_CONFIG_RTS:
+ return "UART_CONFIG_RTS";
+ case CSR_PSKEY_UART_CONFIG_TX_ZERO_EN:
+ return "UART_CONFIG_TX_ZERO_EN";
+ case CSR_PSKEY_UART_CONFIG_NON_BCSP_EN:
+ return "UART_CONFIG_NON_BCSP_EN";
+ case CSR_PSKEY_UART_CONFIG_RX_RATE_DELAY:
+ return "UART_CONFIG_RX_RATE_DELAY";
+ case CSR_PSKEY_UART_SEQ_TIMEOUT:
+ return "UART_SEQ_TIMEOUT";
+ case CSR_PSKEY_UART_SEQ_RETRIES:
+ return "UART_SEQ_RETRIES";
+ case CSR_PSKEY_UART_SEQ_WINSIZE:
+ return "UART_SEQ_WINSIZE";
+ case CSR_PSKEY_UART_USE_CRC_ON_TX:
+ return "UART_USE_CRC_ON_TX";
+ case CSR_PSKEY_UART_HOST_INITIAL_STATE:
+ return "UART_HOST_INITIAL_STATE";
+ case CSR_PSKEY_UART_HOST_ATTENTION_SPAN:
+ return "UART_HOST_ATTENTION_SPAN";
+ case CSR_PSKEY_UART_HOST_WAKEUP_TIME:
+ return "UART_HOST_WAKEUP_TIME";
+ case CSR_PSKEY_UART_HOST_WAKEUP_WAIT:
+ return "UART_HOST_WAKEUP_WAIT";
+ case CSR_PSKEY_BCSP_LM_MODE:
+ return "BCSP_LM_MODE";
+ case CSR_PSKEY_BCSP_LM_SYNC_RETRIES:
+ return "BCSP_LM_SYNC_RETRIES";
+ case CSR_PSKEY_BCSP_LM_TSHY:
+ return "BCSP_LM_TSHY";
+ case CSR_PSKEY_UART_DFU_CONFIG_STOP_BITS:
+ return "UART_DFU_CONFIG_STOP_BITS";
+ case CSR_PSKEY_UART_DFU_CONFIG_PARITY_BIT:
+ return "UART_DFU_CONFIG_PARITY_BIT";
+ case CSR_PSKEY_UART_DFU_CONFIG_FLOW_CTRL_EN:
+ return "UART_DFU_CONFIG_FLOW_CTRL_EN";
+ case CSR_PSKEY_UART_DFU_CONFIG_RTS_AUTO_EN:
+ return "UART_DFU_CONFIG_RTS_AUTO_EN";
+ case CSR_PSKEY_UART_DFU_CONFIG_RTS:
+ return "UART_DFU_CONFIG_RTS";
+ case CSR_PSKEY_UART_DFU_CONFIG_TX_ZERO_EN:
+ return "UART_DFU_CONFIG_TX_ZERO_EN";
+ case CSR_PSKEY_UART_DFU_CONFIG_NON_BCSP_EN:
+ return "UART_DFU_CONFIG_NON_BCSP_EN";
+ case CSR_PSKEY_UART_DFU_CONFIG_RX_RATE_DELAY:
+ return "UART_DFU_CONFIG_RX_RATE_DELAY";
+ case CSR_PSKEY_AMUX_AIO0:
+ return "AMUX_AIO0";
+ case CSR_PSKEY_AMUX_AIO1:
+ return "AMUX_AIO1";
+ case CSR_PSKEY_AMUX_AIO2:
+ return "AMUX_AIO2";
+ case CSR_PSKEY_AMUX_AIO3:
+ return "AMUX_AIO3";
+ case CSR_PSKEY_LOCAL_NAME_SIMPLIFIED:
+ return "LOCAL_NAME_SIMPLIFIED";
+ case CSR_PSKEY_EXTENDED_STUB:
+ return "EXTENDED_STUB";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+int csr_write_varid_valueless(int dd, uint16_t seqnum, uint16_t varid)
+{
+ unsigned char cmd[] = { 0x02, 0x00, 0x09, 0x00,
+ seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+
+ switch (varid) {
+ case CSR_VARID_COLD_RESET:
+ case CSR_VARID_WARM_RESET:
+ case CSR_VARID_COLD_HALT:
+ case CSR_VARID_WARM_HALT:
+ return hci_send_cmd(dd, OGF_VENDOR_CMD, 0x00, sizeof(cmd) + 1, cp);
+ }
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+int csr_write_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ unsigned char cmd[] = { 0x02, 0x00, ((length / 2) + 5) & 0xff, ((length / 2) + 5) >> 8,
+ seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+ memcpy(cp + 11, value, length);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + length + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+int csr_read_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ unsigned char cmd[] = { 0x00, 0x00, ((length / 2) + 5) & 0xff, ((length / 2) + 5) >> 8,
+ seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+ memcpy(cp + 11, value, length);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + length + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ memcpy(value, rp + 11, length);
+
+ return 0;
+}
+
+int csr_read_varid_uint16(int dd, uint16_t seqnum, uint16_t varid, uint16_t *value)
+{
+ unsigned char cmd[] = { 0x00, 0x00, 0x09, 0x00,
+ seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ *value = rp[11] + (rp[12] << 8);
+
+ return 0;
+}
+
+int csr_read_varid_uint32(int dd, uint16_t seqnum, uint16_t varid, uint32_t *value)
+{
+ unsigned char cmd[] = { 0x00, 0x00, 0x09, 0x00,
+ seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ *value = ((rp[11] + (rp[12] << 8)) << 16) + (rp[13] + (rp[14] << 8));
+
+ return 0;
+}
+
+int csr_read_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length)
+{
+ unsigned char cmd[] = { 0x00, 0x00, ((length / 2) + 8) & 0xff, ((length / 2) + 8) >> 8,
+ seqnum & 0xff, seqnum >> 8, 0x03, 0x70, 0x00, 0x00,
+ pskey & 0xff, pskey >> 8,
+ (length / 2) & 0xff, (length / 2) >> 8,
+ stores & 0xff, stores >> 8, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + length - 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ memcpy(value, rp + 17, length);
+
+ return 0;
+}
+
+int csr_write_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length)
+{
+ unsigned char cmd[] = { 0x02, 0x00, ((length / 2) + 8) & 0xff, ((length / 2) + 8) >> 8,
+ seqnum & 0xff, seqnum >> 8, 0x03, 0x70, 0x00, 0x00,
+ pskey & 0xff, pskey >> 8,
+ (length / 2) & 0xff, (length / 2) >> 8,
+ stores & 0xff, stores >> 8, 0x00, 0x00 };
+
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+
+ memcpy(cp + 17, value, length);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = sizeof(cmd) + length - 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+int csr_read_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t *value)
+{
+ uint8_t array[2] = { 0x00, 0x00 };
+ int err;
+
+ err = csr_read_pskey_complex(dd, seqnum, pskey, stores, array, 2);
+
+ *value = array[0] + (array[1] << 8);
+
+ return err;
+}
+
+int csr_write_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t value)
+{
+ uint8_t array[2] = { value & 0xff, value >> 8 };
+
+ return csr_write_pskey_complex(dd, seqnum, pskey, stores, array, 2);
+}
+
+int csr_read_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t *value)
+{
+ uint8_t array[4] = { 0x00, 0x00, 0x00, 0x00 };
+ int err;
+
+ err = csr_read_pskey_complex(dd, seqnum, pskey, stores, array, 4);
+
+ *value = ((array[0] + (array[1] << 8)) << 16) +
+ (array[2] + (array[3] << 8));
+
+ return err;
+}
+
+int csr_write_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t value)
+{
+ uint8_t array[4] = { (value & 0xff0000) >> 16, value >> 24,
+ value & 0xff, (value & 0xff00) >> 8 };
+
+ return csr_write_pskey_complex(dd, seqnum, pskey, stores, array, 4);
+}
+
+int psr_put(uint16_t pskey, uint8_t *value, uint16_t size)
+{
+ struct psr_data *item;
+
+ item = malloc(sizeof(*item));
+ if (!item)
+ return -ENOMEM;
+
+ item->pskey = pskey;
+
+ if (size > 0) {
+ item->value = malloc(size);
+ if (!item->value) {
+ free(item);
+ return -ENOMEM;
+ }
+
+ memcpy(item->value, value, size);
+ item->size = size;
+ } else {
+ item->value = NULL;
+ item->size = 0;
+ }
+
+ item->next = NULL;
+
+ if (!head)
+ head = item;
+ else
+ tail->next = item;
+
+ tail = item;
+
+ return 0;
+}
+
+int psr_get(uint16_t *pskey, uint8_t *value, uint16_t *size)
+{
+ struct psr_data *item = head;
+
+ if (!head)
+ return -ENOENT;
+
+ *pskey = item->pskey;
+
+ if (item->value) {
+ if (value && item->size > 0)
+ memcpy(value, item->value, item->size);
+ free(item->value);
+ *size = item->size;
+ } else
+ *size = 0;
+
+ if (head == tail)
+ tail = NULL;
+
+ head = head->next;
+ free(item);
+
+ return 0;
+}
+
+static int parse_line(char *str)
+{
+ uint8_t array[256];
+ uint16_t value, pskey, length = 0;
+ char *off, *end;
+
+ pskey = strtol(str + 1, NULL, 16);
+ off = strstr(str, "=") + 1;
+ if (!off)
+ return -EIO;
+
+ while (1) {
+ value = strtol(off, &end, 16);
+ if (value == 0 && off == end)
+ break;
+
+ array[length++] = value & 0xff;
+ array[length++] = value >> 8;
+
+ if (*end == '\0')
+ break;
+
+ off = end + 1;
+ }
+
+ return psr_put(pskey, array, length);
+}
+
+int psr_read(const char *filename)
+{
+ struct stat st;
+ char *str, *map, *off, *end;
+ int fd, err = 0;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ if (fstat(fd, &st) < 0) {
+ err = -errno;
+ goto close;
+ }
+
+ map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = -errno;
+ goto close;
+ }
+
+ off = map;
+
+ while (1) {
+ if (*off == '\r' || *off == '\n') {
+ off++;
+ continue;
+ }
+
+ end = strpbrk(off, "\r\n");
+ if (!end)
+ break;
+
+ str = malloc(end - off + 1);
+ if (!str)
+ break;
+
+ memset(str, 0, end - off + 1);
+ strncpy(str, off, end - off);
+ if (*str == '&')
+ parse_line(str);
+
+ free(str);
+ off = end + 1;
+ }
+
+ munmap(map, st.st_size);
+
+close:
+ close(fd);
+
+ return err;
+}
+
+int psr_print(void)
+{
+ uint8_t array[256];
+ uint16_t pskey, length;
+ char *str, val[7];
+ int i;
+
+ while (1) {
+ if (psr_get(&pskey, array, &length) < 0)
+ break;
+
+ str = csr_pskeytoval(pskey);
+ if (!strcasecmp(str, "UNKNOWN")) {
+ sprintf(val, "0x%04x", pskey);
+ str = NULL;
+ }
+
+ printf("// %s%s\n&%04x =", str ? "PSKEY_" : "",
+ str ? str : val, pskey);
+ for (i = 0; i < length / 2; i++)
+ printf(" %02x%02x", array[i * 2 + 1], array[i * 2]);
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/utils/tools/csr.h b/utils/tools/csr.h
new file mode 100644
index 00000000..5df3cb5a
--- /dev/null
+++ b/utils/tools/csr.h
@@ -0,0 +1,552 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+
+#define CSR_VARID_PS_CLR_ALL 0x000b /* valueless */
+#define CSR_VARID_PS_FACTORY_SET 0x000c /* valueless */
+#define CSR_VARID_PS_CLR_ALL_STORES 0x082d /* uint16 */
+#define CSR_VARID_BC01_STATUS 0x2801 /* uint16 */
+#define CSR_VARID_BUILDID 0x2819 /* uint16 */
+#define CSR_VARID_CHIPVER 0x281a /* uint16 */
+#define CSR_VARID_CHIPREV 0x281b /* uint16 */
+#define CSR_VARID_INTERFACE_VERSION 0x2825 /* uint16 */
+#define CSR_VARID_RAND 0x282a /* uint16 */
+#define CSR_VARID_MAX_CRYPT_KEY_LENGTH 0x282c /* uint16 */
+#define CSR_VARID_CHIPANAREV 0x2836 /* uint16 */
+#define CSR_VARID_BUILDID_LOADER 0x2838 /* uint16 */
+#define CSR_VARID_BT_CLOCK 0x2c00 /* uint32 */
+#define CSR_VARID_PS_NEXT 0x3005 /* complex */
+#define CSR_VARID_PS_SIZE 0x3006 /* complex */
+#define CSR_VARID_CRYPT_KEY_LENGTH 0x3008 /* complex */
+#define CSR_VARID_PICONET_INSTANCE 0x3009 /* complex */
+#define CSR_VARID_GET_CLR_EVT 0x300a /* complex */
+#define CSR_VARID_GET_NEXT_BUILDDEF 0x300b /* complex */
+#define CSR_VARID_PS_MEMORY_TYPE 0x3012 /* complex */
+#define CSR_VARID_READ_BUILD_NAME 0x301c /* complex */
+#define CSR_VARID_COLD_RESET 0x4001 /* valueless */
+#define CSR_VARID_WARM_RESET 0x4002 /* valueless */
+#define CSR_VARID_COLD_HALT 0x4003 /* valueless */
+#define CSR_VARID_WARM_HALT 0x4004 /* valueless */
+#define CSR_VARID_INIT_BT_STACK 0x4005 /* valueless */
+#define CSR_VARID_ACTIVATE_BT_STACK 0x4006 /* valueless */
+#define CSR_VARID_ENABLE_TX 0x4007 /* valueless */
+#define CSR_VARID_DISABLE_TX 0x4008 /* valueless */
+#define CSR_VARID_RECAL 0x4009 /* valueless */
+#define CSR_VARID_PS_FACTORY_RESTORE 0x400d /* valueless */
+#define CSR_VARID_PS_FACTORY_RESTORE_ALL 0x400e /* valueless */
+#define CSR_VARID_PS_DEFRAG_RESET 0x400f /* valueless */
+#define CSR_VARID_KILL_VM_APPLICATION 0x4010 /* valueless */
+#define CSR_VARID_HOPPING_ON 0x4011 /* valueless */
+#define CSR_VARID_CANCEL_PAGE 0x4012 /* valueless */
+#define CSR_VARID_PS_CLR 0x4818 /* uint16 */
+#define CSR_VARID_MAP_SCO_PCM 0x481c /* uint16 */
+#define CSR_VARID_SINGLE_CHAN 0x482e /* uint16 */
+#define CSR_VARID_RADIOTEST 0x5004 /* complex */
+#define CSR_VARID_PS_CLR_STORES 0x500c /* complex */
+#define CSR_VARID_NO_VARIABLE 0x6000 /* valueless */
+#define CSR_VARID_CONFIG_UART 0x6802 /* uint16 */
+#define CSR_VARID_PANIC_ARG 0x6805 /* uint16 */
+#define CSR_VARID_FAULT_ARG 0x6806 /* uint16 */
+#define CSR_VARID_MAX_TX_POWER 0x6827 /* int8 */
+#define CSR_VARID_DEFAULT_TX_POWER 0x682b /* int8 */
+#define CSR_VARID_PS 0x7003 /* complex */
+
+#define CSR_PSKEY_BDADDR 0x0001 /* bdaddr / uint16[] = { 0x00A5A5, 0x5b, 0x0002 } */
+#define CSR_PSKEY_COUNTRYCODE 0x0002 /* uint16 */
+#define CSR_PSKEY_CLASSOFDEVICE 0x0003 /* bdcod */
+#define CSR_PSKEY_DEVICE_DRIFT 0x0004 /* uint16 */
+#define CSR_PSKEY_DEVICE_JITTER 0x0005 /* uint16 */
+#define CSR_PSKEY_MAX_ACLS 0x000d /* uint16 */
+#define CSR_PSKEY_MAX_SCOS 0x000e /* uint16 */
+#define CSR_PSKEY_MAX_REMOTE_MASTERS 0x000f /* uint16 */
+#define CSR_PSKEY_ENABLE_MASTERY_WITH_SLAVERY 0x0010 /* bool */
+#define CSR_PSKEY_H_HC_FC_MAX_ACL_PKT_LEN 0x0011 /* uint16 */
+#define CSR_PSKEY_H_HC_FC_MAX_SCO_PKT_LEN 0x0012 /* uint8 */
+#define CSR_PSKEY_H_HC_FC_MAX_ACL_PKTS 0x0013 /* uint16 */
+#define CSR_PSKEY_H_HC_FC_MAX_SCO_PKTS 0x0014 /* uint16 */
+#define CSR_PSKEY_LC_FC_BUFFER_LOW_WATER_MARK 0x0015 /* lc_fc_lwm */
+#define CSR_PSKEY_LC_MAX_TX_POWER 0x0017 /* int16 */
+#define CSR_PSKEY_TX_GAIN_RAMP 0x001d /* uint16 */
+#define CSR_PSKEY_LC_POWER_TABLE 0x001e /* power_setting[] */
+#define CSR_PSKEY_LC_PEER_POWER_PERIOD 0x001f /* TIME */
+#define CSR_PSKEY_LC_FC_POOLS_LOW_WATER_MARK 0x0020 /* lc_fc_lwm */
+#define CSR_PSKEY_LC_DEFAULT_TX_POWER 0x0021 /* int16 */
+#define CSR_PSKEY_LC_RSSI_GOLDEN_RANGE 0x0022 /* uint8 */
+#define CSR_PSKEY_LC_COMBO_DISABLE_PIO_MASK 0x0028 /* uint16[] */
+#define CSR_PSKEY_LC_COMBO_PRIORITY_PIO_MASK 0x0029 /* uint16[] */
+#define CSR_PSKEY_LC_COMBO_DOT11_CHANNEL_PIO_BASE 0x002a /* uint16 */
+#define CSR_PSKEY_LC_COMBO_DOT11_BLOCK_CHANNELS 0x002b /* uint16 */
+#define CSR_PSKEY_LC_MAX_TX_POWER_NO_RSSI 0x002d /* int8 */
+#define CSR_PSKEY_LC_CONNECTION_RX_WINDOW 0x002e /* uint16 */
+#define CSR_PSKEY_LC_COMBO_DOT11_TX_PROTECTION_MODE 0x0030 /* uint16 */
+#define CSR_PSKEY_LC_ENHANCED_POWER_TABLE 0x0031 /* enhanced_power_setting[] */
+#define CSR_PSKEY_LC_WIDEBAND_RSSI_CONFIG 0x0032 /* wideband_rssi_config */
+#define CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_LEAD 0x0033 /* uint16 */
+#define CSR_PSKEY_BT_CLOCK_INIT 0x0034 /* uint32 */
+#define CSR_PSKEY_TX_MR_MOD_DELAY 0x0038 /* uint8 */
+#define CSR_PSKEY_RX_MR_SYNC_TIMING 0x0039 /* uint16 */
+#define CSR_PSKEY_RX_MR_SYNC_CONFIG 0x003a /* uint16 */
+#define CSR_PSKEY_LC_LOST_SYNC_SLOTS 0x003b /* uint16 */
+#define CSR_PSKEY_RX_MR_SAMP_CONFIG 0x003c /* uint16 */
+#define CSR_PSKEY_AGC_HYST_LEVELS 0x003d /* agc_hyst_config */
+#define CSR_PSKEY_RX_LEVEL_LOW_SIGNAL 0x003e /* uint16 */
+#define CSR_PSKEY_AGC_IQ_LVL_VALUES 0x003f /* IQ_LVL_VAL[] */
+#define CSR_PSKEY_MR_FTRIM_OFFSET_12DB 0x0040 /* uint16 */
+#define CSR_PSKEY_MR_FTRIM_OFFSET_6DB 0x0041 /* uint16 */
+#define CSR_PSKEY_NO_CAL_ON_BOOT 0x0042 /* bool */
+#define CSR_PSKEY_RSSI_HI_TARGET 0x0043 /* uint8 */
+#define CSR_PSKEY_PREFERRED_MIN_ATTENUATION 0x0044 /* uint8 */
+#define CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_OVERRIDE 0x0045 /* bool */
+#define CSR_PSKEY_LC_MULTISLOT_HOLDOFF 0x0047 /* TIME */
+#define CSR_PSKEY_FREE_KEY_PIGEON_HOLE 0x00c9 /* uint16 */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR0 0x00ca /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR1 0x00cb /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR2 0x00cc /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR3 0x00cd /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR4 0x00ce /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR5 0x00cf /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR6 0x00d0 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR7 0x00d1 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR8 0x00d2 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR9 0x00d3 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR10 0x00d4 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR11 0x00d5 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR12 0x00d6 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR13 0x00d7 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR14 0x00d8 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LINK_KEY_BD_ADDR15 0x00d9 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_ENC_KEY_LMIN 0x00da /* uint16 */
+#define CSR_PSKEY_ENC_KEY_LMAX 0x00db /* uint16 */
+#define CSR_PSKEY_LOCAL_SUPPORTED_FEATURES 0x00ef /* uint16[] = { 0xffff, 0xfe8f, 0xf99b, 0x8000 }*/
+#define CSR_PSKEY_LM_USE_UNIT_KEY 0x00f0 /* bool */
+#define CSR_PSKEY_HCI_NOP_DISABLE 0x00f2 /* bool */
+#define CSR_PSKEY_LM_MAX_EVENT_FILTERS 0x00f4 /* uint8 */
+#define CSR_PSKEY_LM_USE_ENC_MODE_BROADCAST 0x00f5 /* bool */
+#define CSR_PSKEY_LM_TEST_SEND_ACCEPTED_TWICE 0x00f6 /* bool */
+#define CSR_PSKEY_LM_MAX_PAGE_HOLD_TIME 0x00f7 /* uint16 */
+#define CSR_PSKEY_AFH_ADAPTATION_RESPONSE_TIME 0x00f8 /* uint16 */
+#define CSR_PSKEY_AFH_OPTIONS 0x00f9 /* uint16 */
+#define CSR_PSKEY_AFH_RSSI_RUN_PERIOD 0x00fa /* uint16 */
+#define CSR_PSKEY_AFH_REENABLE_CHANNEL_TIME 0x00fb /* uint16 */
+#define CSR_PSKEY_NO_DROP_ON_ACR_MS_FAIL 0x00fc /* bool */
+#define CSR_PSKEY_MAX_PRIVATE_KEYS 0x00fd /* uint8 */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR0 0x00fe /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR1 0x00ff /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR2 0x0100 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR3 0x0101 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR4 0x0102 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR5 0x0103 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR6 0x0104 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR7 0x0105 /* LM_LINK_KEY_BD_ADDR_T */
+#define CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS 0x0106 /* uint16[] = { 0xffff, 0x03ff, 0xfffe, 0xffff, 0xffff, 0xffff, 0x0ff3, 0xfff8, 0x003f } */
+#define CSR_PSKEY_LM_MAX_ABSENCE_INDEX 0x0107 /* uint8 */
+#define CSR_PSKEY_DEVICE_NAME 0x0108 /* uint16[] */
+#define CSR_PSKEY_AFH_RSSI_THRESHOLD 0x0109 /* uint16 */
+#define CSR_PSKEY_LM_CASUAL_SCAN_INTERVAL 0x010a /* uint16 */
+#define CSR_PSKEY_AFH_MIN_MAP_CHANGE 0x010b /* uint16[] */
+#define CSR_PSKEY_AFH_RSSI_LP_RUN_PERIOD 0x010c /* uint16 */
+#define CSR_PSKEY_HCI_LMP_LOCAL_VERSION 0x010d /* uint16 */
+#define CSR_PSKEY_LMP_REMOTE_VERSION 0x010e /* uint8 */
+#define CSR_PSKEY_HOLD_ERROR_MESSAGE_NUMBER 0x0113 /* uint16 */
+#define CSR_PSKEY_DFU_ATTRIBUTES 0x0136 /* uint8 */
+#define CSR_PSKEY_DFU_DETACH_TO 0x0137 /* uint16 */
+#define CSR_PSKEY_DFU_TRANSFER_SIZE 0x0138 /* uint16 */
+#define CSR_PSKEY_DFU_ENABLE 0x0139 /* bool */
+#define CSR_PSKEY_DFU_LIN_REG_ENABLE 0x013a /* bool */
+#define CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_MSB 0x015e /* uint16[] */
+#define CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_LSB 0x015f /* uint16[] */
+#define CSR_PSKEY_DFUENC_VMAPP_PK_M_DASH 0x0160 /* uint16 */
+#define CSR_PSKEY_DFUENC_VMAPP_PK_R2N_MSB 0x0161 /* uint16[] */
+#define CSR_PSKEY_DFUENC_VMAPP_PK_R2N_LSB 0x0162 /* uint16[] */
+#define CSR_PSKEY_BCSP_LM_PS_BLOCK 0x0192 /* BCSP_LM_PS_BLOCK */
+#define CSR_PSKEY_HOSTIO_FC_PS_BLOCK 0x0193 /* HOSTIO_FC_PS_BLOCK */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO0 0x0194 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO1 0x0195 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO2 0x0196 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO3 0x0197 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO4 0x0198 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO5 0x0199 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO6 0x019a /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO7 0x019b /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO8 0x019c /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO9 0x019d /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO10 0x019e /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO11 0x019f /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO12 0x01a0 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO13 0x01a1 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO14 0x01a2 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO15 0x01a3 /* PROTOCOL_INFO */
+#define CSR_PSKEY_HOSTIO_UART_RESET_TIMEOUT 0x01a4 /* TIME */
+#define CSR_PSKEY_HOSTIO_USE_HCI_EXTN 0x01a5 /* bool */
+#define CSR_PSKEY_HOSTIO_USE_HCI_EXTN_CCFC 0x01a6 /* bool */
+#define CSR_PSKEY_HOSTIO_HCI_EXTN_PAYLOAD_SIZE 0x01a7 /* uint16 */
+#define CSR_PSKEY_BCSP_LM_CNF_CNT_LIMIT 0x01aa /* uint16 */
+#define CSR_PSKEY_HOSTIO_MAP_SCO_PCM 0x01ab /* bool */
+#define CSR_PSKEY_HOSTIO_AWKWARD_PCM_SYNC 0x01ac /* bool */
+#define CSR_PSKEY_HOSTIO_BREAK_POLL_PERIOD 0x01ad /* TIME */
+#define CSR_PSKEY_HOSTIO_MIN_UART_HCI_SCO_SIZE 0x01ae /* uint16 */
+#define CSR_PSKEY_HOSTIO_MAP_SCO_CODEC 0x01b0 /* bool */
+#define CSR_PSKEY_PCM_CVSD_TX_HI_FREQ_BOOST 0x01b1 /* uint16 */
+#define CSR_PSKEY_PCM_CVSD_RX_HI_FREQ_BOOST 0x01b2 /* uint16 */
+#define CSR_PSKEY_PCM_CONFIG32 0x01b3 /* uint32 */
+#define CSR_PSKEY_USE_OLD_BCSP_LE 0x01b4 /* uint16 */
+#define CSR_PSKEY_PCM_CVSD_USE_NEW_FILTER 0x01b5 /* bool */
+#define CSR_PSKEY_PCM_FORMAT 0x01b6 /* uint16 */
+#define CSR_PSKEY_CODEC_OUT_GAIN 0x01b7 /* uint16 */
+#define CSR_PSKEY_CODEC_IN_GAIN 0x01b8 /* uint16 */
+#define CSR_PSKEY_CODEC_PIO 0x01b9 /* uint16 */
+#define CSR_PSKEY_PCM_LOW_JITTER_CONFIG 0x01ba /* uint32 */
+#define CSR_PSKEY_HOSTIO_SCO_PCM_THRESHOLDS 0x01bb /* uint16[] */
+#define CSR_PSKEY_HOSTIO_SCO_HCI_THRESHOLDS 0x01bc /* uint16[] */
+#define CSR_PSKEY_HOSTIO_MAP_SCO_PCM_SLOT 0x01bd /* uint16 */
+#define CSR_PSKEY_UART_BAUDRATE 0x01be /* uint16 */
+#define CSR_PSKEY_UART_CONFIG_BCSP 0x01bf /* uint16 */
+#define CSR_PSKEY_UART_CONFIG_H4 0x01c0 /* uint16 */
+#define CSR_PSKEY_UART_CONFIG_H5 0x01c1 /* uint16 */
+#define CSR_PSKEY_UART_CONFIG_USR 0x01c2 /* uint16 */
+#define CSR_PSKEY_UART_TX_CRCS 0x01c3 /* bool */
+#define CSR_PSKEY_UART_ACK_TIMEOUT 0x01c4 /* uint16 */
+#define CSR_PSKEY_UART_TX_MAX_ATTEMPTS 0x01c5 /* uint16 */
+#define CSR_PSKEY_UART_TX_WINDOW_SIZE 0x01c6 /* uint16 */
+#define CSR_PSKEY_UART_HOST_WAKE 0x01c7 /* uint16[] */
+#define CSR_PSKEY_HOSTIO_THROTTLE_TIMEOUT 0x01c8 /* TIME */
+#define CSR_PSKEY_PCM_ALWAYS_ENABLE 0x01c9 /* bool */
+#define CSR_PSKEY_UART_HOST_WAKE_SIGNAL 0x01ca /* uint16 */
+#define CSR_PSKEY_UART_CONFIG_H4DS 0x01cb /* uint16 */
+#define CSR_PSKEY_H4DS_WAKE_DURATION 0x01cc /* uint16 */
+#define CSR_PSKEY_H4DS_MAXWU 0x01cd /* uint16 */
+#define CSR_PSKEY_H4DS_LE_TIMER_PERIOD 0x01cf /* uint16 */
+#define CSR_PSKEY_H4DS_TWU_TIMER_PERIOD 0x01d0 /* uint16 */
+#define CSR_PSKEY_H4DS_UART_IDLE_TIMER_PERIOD 0x01d1 /* uint16 */
+#define CSR_PSKEY_ANA_FTRIM 0x01f6 /* uint16 */
+#define CSR_PSKEY_WD_TIMEOUT 0x01f7 /* TIME */
+#define CSR_PSKEY_WD_PERIOD 0x01f8 /* TIME */
+#define CSR_PSKEY_HOST_INTERFACE 0x01f9 /* phys_bus */
+#define CSR_PSKEY_HQ_HOST_TIMEOUT 0x01fb /* TIME */
+#define CSR_PSKEY_HQ_ACTIVE 0x01fc /* bool */
+#define CSR_PSKEY_BCCMD_SECURITY_ACTIVE 0x01fd /* bool */
+#define CSR_PSKEY_ANA_FREQ 0x01fe /* uint16 */
+#define CSR_PSKEY_PIO_PROTECT_MASK 0x0202 /* uint16 */
+#define CSR_PSKEY_PMALLOC_SIZES 0x0203 /* uint16[] */
+#define CSR_PSKEY_UART_BAUD_RATE 0x0204 /* uint16 */
+#define CSR_PSKEY_UART_CONFIG 0x0205 /* uint16 */
+#define CSR_PSKEY_STUB 0x0207 /* uint16 */
+#define CSR_PSKEY_TXRX_PIO_CONTROL 0x0209 /* uint16 */
+#define CSR_PSKEY_ANA_RX_LEVEL 0x020b /* uint16 */
+#define CSR_PSKEY_ANA_RX_FTRIM 0x020c /* uint16 */
+#define CSR_PSKEY_PSBC_DATA_VERSION 0x020d /* uint16 */
+#define CSR_PSKEY_PCM0_ATTENUATION 0x020f /* uint16 */
+#define CSR_PSKEY_LO_LVL_MAX 0x0211 /* uint16 */
+#define CSR_PSKEY_LO_ADC_AMPL_MIN 0x0212 /* uint16 */
+#define CSR_PSKEY_LO_ADC_AMPL_MAX 0x0213 /* uint16 */
+#define CSR_PSKEY_IQ_TRIM_CHANNEL 0x0214 /* uint16 */
+#define CSR_PSKEY_IQ_TRIM_GAIN 0x0215 /* uint16 */
+#define CSR_PSKEY_IQ_TRIM_ENABLE 0x0216 /* iq_trim_enable_flag */
+#define CSR_PSKEY_TX_OFFSET_HALF_MHZ 0x0217 /* int16 */
+#define CSR_PSKEY_GBL_MISC_ENABLES 0x0221 /* uint16 */
+#define CSR_PSKEY_UART_SLEEP_TIMEOUT 0x0222 /* uint16 */
+#define CSR_PSKEY_DEEP_SLEEP_STATE 0x0229 /* deep_sleep_state */
+#define CSR_PSKEY_IQ_ENABLE_PHASE_TRIM 0x022d /* bool */
+#define CSR_PSKEY_HCI_HANDLE_FREEZE_PERIOD 0x0237 /* TIME */
+#define CSR_PSKEY_MAX_FROZEN_HCI_HANDLES 0x0238 /* uint16 */
+#define CSR_PSKEY_PAGETABLE_DESTRUCTION_DELAY 0x0239 /* TIME */
+#define CSR_PSKEY_IQ_TRIM_PIO_SETTINGS 0x023a /* uint8 */
+#define CSR_PSKEY_USE_EXTERNAL_CLOCK 0x023b /* bool */
+#define CSR_PSKEY_DEEP_SLEEP_WAKE_CTS 0x023c /* uint16 */
+#define CSR_PSKEY_FC_HC2H_FLUSH_DELAY 0x023d /* TIME */
+#define CSR_PSKEY_RX_HIGHSIDE 0x023e /* bool */
+#define CSR_PSKEY_TX_PRE_LVL 0x0240 /* uint8 */
+#define CSR_PSKEY_RX_SINGLE_ENDED 0x0242 /* bool */
+#define CSR_PSKEY_TX_FILTER_CONFIG 0x0243 /* uint32 */
+#define CSR_PSKEY_CLOCK_REQUEST_ENABLE 0x0246 /* uint16 */
+#define CSR_PSKEY_RX_MIN_ATTEN 0x0249 /* uint16 */
+#define CSR_PSKEY_XTAL_TARGET_AMPLITUDE 0x024b /* uint8 */
+#define CSR_PSKEY_PCM_MIN_CPU_CLOCK 0x024d /* uint16 */
+#define CSR_PSKEY_HOST_INTERFACE_PIO_USB 0x0250 /* uint16 */
+#define CSR_PSKEY_CPU_IDLE_MODE 0x0251 /* cpu_idle_mode */
+#define CSR_PSKEY_DEEP_SLEEP_CLEAR_RTS 0x0252 /* bool */
+#define CSR_PSKEY_RF_RESONANCE_TRIM 0x0254 /* uint16 */
+#define CSR_PSKEY_DEEP_SLEEP_PIO_WAKE 0x0255 /* uint16 */
+#define CSR_PSKEY_DRAIN_BORE_TIMERS 0x0256 /* uint32[] */
+#define CSR_PSKEY_DRAIN_TX_POWER_BASE 0x0257 /* uint16 */
+#define CSR_PSKEY_MODULE_ID 0x0259 /* uint32 */
+#define CSR_PSKEY_MODULE_DESIGN 0x025a /* uint16 */
+#define CSR_PSKEY_MODULE_SECURITY_CODE 0x025c /* uint16[] */
+#define CSR_PSKEY_VM_DISABLE 0x025d /* bool */
+#define CSR_PSKEY_MOD_MANUF0 0x025e /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF1 0x025f /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF2 0x0260 /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF3 0x0261 /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF4 0x0262 /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF5 0x0263 /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF6 0x0264 /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF7 0x0265 /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF8 0x0266 /* uint16[] */
+#define CSR_PSKEY_MOD_MANUF9 0x0267 /* uint16[] */
+#define CSR_PSKEY_DUT_VM_DISABLE 0x0268 /* bool */
+#define CSR_PSKEY_USR0 0x028a /* uint16[] */
+#define CSR_PSKEY_USR1 0x028b /* uint16[] */
+#define CSR_PSKEY_USR2 0x028c /* uint16[] */
+#define CSR_PSKEY_USR3 0x028d /* uint16[] */
+#define CSR_PSKEY_USR4 0x028e /* uint16[] */
+#define CSR_PSKEY_USR5 0x028f /* uint16[] */
+#define CSR_PSKEY_USR6 0x0290 /* uint16[] */
+#define CSR_PSKEY_USR7 0x0291 /* uint16[] */
+#define CSR_PSKEY_USR8 0x0292 /* uint16[] */
+#define CSR_PSKEY_USR9 0x0293 /* uint16[] */
+#define CSR_PSKEY_USR10 0x0294 /* uint16[] */
+#define CSR_PSKEY_USR11 0x0295 /* uint16[] */
+#define CSR_PSKEY_USR12 0x0296 /* uint16[] */
+#define CSR_PSKEY_USR13 0x0297 /* uint16[] */
+#define CSR_PSKEY_USR14 0x0298 /* uint16[] */
+#define CSR_PSKEY_USR15 0x0299 /* uint16[] */
+#define CSR_PSKEY_USR16 0x029a /* uint16[] */
+#define CSR_PSKEY_USR17 0x029b /* uint16[] */
+#define CSR_PSKEY_USR18 0x029c /* uint16[] */
+#define CSR_PSKEY_USR19 0x029d /* uint16[] */
+#define CSR_PSKEY_USR20 0x029e /* uint16[] */
+#define CSR_PSKEY_USR21 0x029f /* uint16[] */
+#define CSR_PSKEY_USR22 0x02a0 /* uint16[] */
+#define CSR_PSKEY_USR23 0x02a1 /* uint16[] */
+#define CSR_PSKEY_USR24 0x02a2 /* uint16[] */
+#define CSR_PSKEY_USR25 0x02a3 /* uint16[] */
+#define CSR_PSKEY_USR26 0x02a4 /* uint16[] */
+#define CSR_PSKEY_USR27 0x02a5 /* uint16[] */
+#define CSR_PSKEY_USR28 0x02a6 /* uint16[] */
+#define CSR_PSKEY_USR29 0x02a7 /* uint16[] */
+#define CSR_PSKEY_USR30 0x02a8 /* uint16[] */
+#define CSR_PSKEY_USR31 0x02a9 /* uint16[] */
+#define CSR_PSKEY_USR32 0x02aa /* uint16[] */
+#define CSR_PSKEY_USR33 0x02ab /* uint16[] */
+#define CSR_PSKEY_USR34 0x02ac /* uint16[] */
+#define CSR_PSKEY_USR35 0x02ad /* uint16[] */
+#define CSR_PSKEY_USR36 0x02ae /* uint16[] */
+#define CSR_PSKEY_USR37 0x02af /* uint16[] */
+#define CSR_PSKEY_USR38 0x02b0 /* uint16[] */
+#define CSR_PSKEY_USR39 0x02b1 /* uint16[] */
+#define CSR_PSKEY_USR40 0x02b2 /* uint16[] */
+#define CSR_PSKEY_USR41 0x02b3 /* uint16[] */
+#define CSR_PSKEY_USR42 0x02b4 /* uint16[] */
+#define CSR_PSKEY_USR43 0x02b5 /* uint16[] */
+#define CSR_PSKEY_USR44 0x02b6 /* uint16[] */
+#define CSR_PSKEY_USR45 0x02b7 /* uint16[] */
+#define CSR_PSKEY_USR46 0x02b8 /* uint16[] */
+#define CSR_PSKEY_USR47 0x02b9 /* uint16[] */
+#define CSR_PSKEY_USR48 0x02ba /* uint16[] */
+#define CSR_PSKEY_USR49 0x02bb /* uint16[] */
+#define CSR_PSKEY_USB_VERSION 0x02bc /* uint16 */
+#define CSR_PSKEY_USB_DEVICE_CLASS_CODES 0x02bd /* usbclass */
+#define CSR_PSKEY_USB_VENDOR_ID 0x02be /* uint16 */
+#define CSR_PSKEY_USB_PRODUCT_ID 0x02bf /* uint16 */
+#define CSR_PSKEY_USB_MANUF_STRING 0x02c1 /* unicodestring */
+#define CSR_PSKEY_USB_PRODUCT_STRING 0x02c2 /* unicodestring */
+#define CSR_PSKEY_USB_SERIAL_NUMBER_STRING 0x02c3 /* unicodestring */
+#define CSR_PSKEY_USB_CONFIG_STRING 0x02c4 /* unicodestring */
+#define CSR_PSKEY_USB_ATTRIBUTES 0x02c5 /* uint8 */
+#define CSR_PSKEY_USB_MAX_POWER 0x02c6 /* uint16 */
+#define CSR_PSKEY_USB_BT_IF_CLASS_CODES 0x02c7 /* usbclass */
+#define CSR_PSKEY_USB_LANGID 0x02c9 /* uint16 */
+#define CSR_PSKEY_USB_DFU_CLASS_CODES 0x02ca /* usbclass */
+#define CSR_PSKEY_USB_DFU_PRODUCT_ID 0x02cb /* uint16 */
+#define CSR_PSKEY_USB_PIO_DETACH 0x02ce /* uint16 */
+#define CSR_PSKEY_USB_PIO_WAKEUP 0x02cf /* uint16 */
+#define CSR_PSKEY_USB_PIO_PULLUP 0x02d0 /* uint16 */
+#define CSR_PSKEY_USB_PIO_VBUS 0x02d1 /* uint16 */
+#define CSR_PSKEY_USB_PIO_WAKE_TIMEOUT 0x02d2 /* uint16 */
+#define CSR_PSKEY_USB_PIO_RESUME 0x02d3 /* uint16 */
+#define CSR_PSKEY_USB_BT_SCO_IF_CLASS_CODES 0x02d4 /* usbclass */
+#define CSR_PSKEY_USB_SUSPEND_PIO_LEVEL 0x02d5 /* uint16 */
+#define CSR_PSKEY_USB_SUSPEND_PIO_DIR 0x02d6 /* uint16 */
+#define CSR_PSKEY_USB_SUSPEND_PIO_MASK 0x02d7 /* uint16 */
+#define CSR_PSKEY_USB_ENDPOINT_0_MAX_PACKET_SIZE 0x02d8 /* uint8 */
+#define CSR_PSKEY_USB_CONFIG 0x02d9 /* uint16 */
+#define CSR_PSKEY_RADIOTEST_ATTEN_INIT 0x0320 /* uint16 */
+#define CSR_PSKEY_RADIOTEST_FIRST_TRIM_TIME 0x0326 /* TIME */
+#define CSR_PSKEY_RADIOTEST_SUBSEQUENT_TRIM_TIME 0x0327 /* TIME */
+#define CSR_PSKEY_RADIOTEST_LO_LVL_TRIM_ENABLE 0x0328 /* bool */
+#define CSR_PSKEY_RADIOTEST_DISABLE_MODULATION 0x032c /* bool */
+#define CSR_PSKEY_RFCOMM_FCON_THRESHOLD 0x0352 /* uint16 */
+#define CSR_PSKEY_RFCOMM_FCOFF_THRESHOLD 0x0353 /* uint16 */
+#define CSR_PSKEY_IPV6_STATIC_ADDR 0x0354 /* uint16[] */
+#define CSR_PSKEY_IPV4_STATIC_ADDR 0x0355 /* uint32 */
+#define CSR_PSKEY_IPV6_STATIC_PREFIX_LEN 0x0356 /* uint8 */
+#define CSR_PSKEY_IPV6_STATIC_ROUTER_ADDR 0x0357 /* uint16[] */
+#define CSR_PSKEY_IPV4_STATIC_SUBNET_MASK 0x0358 /* uint32 */
+#define CSR_PSKEY_IPV4_STATIC_ROUTER_ADDR 0x0359 /* uint32 */
+#define CSR_PSKEY_MDNS_NAME 0x035a /* char[] */
+#define CSR_PSKEY_FIXED_PIN 0x035b /* uint8[] */
+#define CSR_PSKEY_MDNS_PORT 0x035c /* uint16 */
+#define CSR_PSKEY_MDNS_TTL 0x035d /* uint8 */
+#define CSR_PSKEY_MDNS_IPV4_ADDR 0x035e /* uint32 */
+#define CSR_PSKEY_ARP_CACHE_TIMEOUT 0x035f /* uint16 */
+#define CSR_PSKEY_HFP_POWER_TABLE 0x0360 /* uint16[] */
+#define CSR_PSKEY_DRAIN_BORE_TIMER_COUNTERS 0x03e7 /* uint32[] */
+#define CSR_PSKEY_DRAIN_BORE_COUNTERS 0x03e6 /* uint32[] */
+#define CSR_PSKEY_LOOP_FILTER_TRIM 0x03e4 /* uint16 */
+#define CSR_PSKEY_DRAIN_BORE_CURRENT_PEAK 0x03e3 /* uint32[] */
+#define CSR_PSKEY_VM_E2_CACHE_LIMIT 0x03e2 /* uint16 */
+#define CSR_PSKEY_FORCE_16MHZ_REF_PIO 0x03e1 /* uint16 */
+#define CSR_PSKEY_CDMA_LO_REF_LIMITS 0x03df /* uint16 */
+#define CSR_PSKEY_CDMA_LO_ERROR_LIMITS 0x03de /* uint16 */
+#define CSR_PSKEY_CLOCK_STARTUP_DELAY 0x03dd /* uint16 */
+#define CSR_PSKEY_DEEP_SLEEP_CORRECTION_FACTOR 0x03dc /* int16 */
+#define CSR_PSKEY_TEMPERATURE_CALIBRATION 0x03db /* temperature_calibration */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA 0x03da /* temperature_calibration[] */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL 0x03d9 /* temperature_calibration[] */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB 0x03d8 /* temperature_calibration[] */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_ANA_FTRIM 0x03d7 /* temperature_calibration[] */
+#define CSR_PSKEY_TEST_DELTA_OFFSET 0x03d6 /* uint16 */
+#define CSR_PSKEY_RX_DYNAMIC_LVL_OFFSET 0x03d4 /* uint16 */
+#define CSR_PSKEY_TEST_FORCE_OFFSET 0x03d3 /* bool */
+#define CSR_PSKEY_RF_TRAP_BAD_DIVISION_RATIOS 0x03cf /* uint16 */
+#define CSR_PSKEY_RADIOTEST_CDMA_LO_REF_LIMITS 0x03ce /* uint16 */
+#define CSR_PSKEY_INITIAL_BOOTMODE 0x03cd /* int16 */
+#define CSR_PSKEY_ONCHIP_HCI_CLIENT 0x03cc /* bool */
+#define CSR_PSKEY_RX_ATTEN_BACKOFF 0x03ca /* uint16 */
+#define CSR_PSKEY_RX_ATTEN_UPDATE_RATE 0x03c9 /* uint16 */
+#define CSR_PSKEY_SYNTH_TXRX_THRESHOLDS 0x03c7 /* uint16 */
+#define CSR_PSKEY_MIN_WAIT_STATES 0x03c6 /* uint16 */
+#define CSR_PSKEY_RSSI_CORRECTION 0x03c5 /* int8 */
+#define CSR_PSKEY_SCHED_THROTTLE_TIMEOUT 0x03c4 /* TIME */
+#define CSR_PSKEY_DEEP_SLEEP_USE_EXTERNAL_CLOCK 0x03c3 /* bool */
+#define CSR_PSKEY_TRIM_RADIO_FILTERS 0x03c2 /* uint16 */
+#define CSR_PSKEY_TRANSMIT_OFFSET 0x03c1 /* int16 */
+#define CSR_PSKEY_USB_VM_CONTROL 0x03c0 /* bool */
+#define CSR_PSKEY_MR_ANA_RX_FTRIM 0x03bf /* uint16 */
+#define CSR_PSKEY_I2C_CONFIG 0x03be /* uint16 */
+#define CSR_PSKEY_IQ_LVL_RX 0x03bd /* uint16 */
+#define CSR_PSKEY_MR_TX_FILTER_CONFIG 0x03bb /* uint32 */
+#define CSR_PSKEY_MR_TX_CONFIG2 0x03ba /* uint16 */
+#define CSR_PSKEY_USB_DONT_RESET_BOOTMODE_ON_HOST_RESET 0x03b9 /* bool */
+#define CSR_PSKEY_LC_USE_THROTTLING 0x03b8 /* bool */
+#define CSR_PSKEY_CHARGER_TRIM 0x03b7 /* uint16 */
+#define CSR_PSKEY_CLOCK_REQUEST_FEATURES 0x03b6 /* uint16 */
+#define CSR_PSKEY_TRANSMIT_OFFSET_CLASS1 0x03b4 /* int16 */
+#define CSR_PSKEY_TX_AVOID_PA_CLASS1_PIO 0x03b3 /* uint16 */
+#define CSR_PSKEY_MR_PIO_CONFIG 0x03b2 /* uint16 */
+#define CSR_PSKEY_UART_CONFIG2 0x03b1 /* uint8 */
+#define CSR_PSKEY_CLASS1_IQ_LVL 0x03b0 /* uint16 */
+#define CSR_PSKEY_CLASS1_TX_CONFIG2 0x03af /* uint16 */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1 0x03ae /* temperature_calibration[] */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1 0x03ad /* temperature_calibration[] */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR 0x03ac /* temperature_calibration[] */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER 0x03ab /* temperature_calibration[] */
+#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD 0x03aa /* temperature_calibration[] */
+#define CSR_PSKEY_RX_MR_EQ_TAPS 0x03a9 /* uint16[] */
+#define CSR_PSKEY_TX_PRE_LVL_CLASS1 0x03a8 /* uint8 */
+#define CSR_PSKEY_ANALOGUE_ATTENUATOR 0x03a7 /* bool */
+#define CSR_PSKEY_MR_RX_FILTER_TRIM 0x03a6 /* uint16 */
+#define CSR_PSKEY_MR_RX_FILTER_RESPONSE 0x03a5 /* int16[] */
+#define CSR_PSKEY_PIO_WAKEUP_STATE 0x039f /* uint16 */
+#define CSR_PSKEY_MR_TX_IF_ATTEN_OFF_TEMP 0x0394 /* int16 */
+#define CSR_PSKEY_LO_DIV_LATCH_BYPASS 0x0393 /* bool */
+#define CSR_PSKEY_LO_VCO_STANDBY 0x0392 /* bool */
+#define CSR_PSKEY_SLOW_CLOCK_FILTER_SHIFT 0x0391 /* uint16 */
+#define CSR_PSKEY_SLOW_CLOCK_FILTER_DIVIDER 0x0390 /* uint16 */
+#define CSR_PSKEY_USB_ATTRIBUTES_POWER 0x03f2 /* bool */
+#define CSR_PSKEY_USB_ATTRIBUTES_WAKEUP 0x03f3 /* bool */
+#define CSR_PSKEY_DFU_ATTRIBUTES_MANIFESTATION_TOLERANT 0x03f4 /* bool */
+#define CSR_PSKEY_DFU_ATTRIBUTES_CAN_UPLOAD 0x03f5 /* bool */
+#define CSR_PSKEY_DFU_ATTRIBUTES_CAN_DOWNLOAD 0x03f6 /* bool */
+#define CSR_PSKEY_UART_CONFIG_STOP_BITS 0x03fc /* bool */
+#define CSR_PSKEY_UART_CONFIG_PARITY_BIT 0x03fd /* uint16 */
+#define CSR_PSKEY_UART_CONFIG_FLOW_CTRL_EN 0x03fe /* bool */
+#define CSR_PSKEY_UART_CONFIG_RTS_AUTO_EN 0x03ff /* bool */
+#define CSR_PSKEY_UART_CONFIG_RTS 0x0400 /* bool */
+#define CSR_PSKEY_UART_CONFIG_TX_ZERO_EN 0x0401 /* bool */
+#define CSR_PSKEY_UART_CONFIG_NON_BCSP_EN 0x0402 /* bool */
+#define CSR_PSKEY_UART_CONFIG_RX_RATE_DELAY 0x0403 /* uint16 */
+#define CSR_PSKEY_UART_SEQ_TIMEOUT 0x0405 /* uint16 */
+#define CSR_PSKEY_UART_SEQ_RETRIES 0x0406 /* uint16 */
+#define CSR_PSKEY_UART_SEQ_WINSIZE 0x0407 /* uint16 */
+#define CSR_PSKEY_UART_USE_CRC_ON_TX 0x0408 /* bool */
+#define CSR_PSKEY_UART_HOST_INITIAL_STATE 0x0409 /* hwakeup_state */
+#define CSR_PSKEY_UART_HOST_ATTENTION_SPAN 0x040a /* uint16 */
+#define CSR_PSKEY_UART_HOST_WAKEUP_TIME 0x040b /* uint16 */
+#define CSR_PSKEY_UART_HOST_WAKEUP_WAIT 0x040c /* uint16 */
+#define CSR_PSKEY_BCSP_LM_MODE 0x0410 /* uint16 */
+#define CSR_PSKEY_BCSP_LM_SYNC_RETRIES 0x0411 /* uint16 */
+#define CSR_PSKEY_BCSP_LM_TSHY 0x0412 /* uint16 */
+#define CSR_PSKEY_UART_DFU_CONFIG_STOP_BITS 0x0417 /* bool */
+#define CSR_PSKEY_UART_DFU_CONFIG_PARITY_BIT 0x0418 /* uint16 */
+#define CSR_PSKEY_UART_DFU_CONFIG_FLOW_CTRL_EN 0x0419 /* bool */
+#define CSR_PSKEY_UART_DFU_CONFIG_RTS_AUTO_EN 0x041a /* bool */
+#define CSR_PSKEY_UART_DFU_CONFIG_RTS 0x041b /* bool */
+#define CSR_PSKEY_UART_DFU_CONFIG_TX_ZERO_EN 0x041c /* bool */
+#define CSR_PSKEY_UART_DFU_CONFIG_NON_BCSP_EN 0x041d /* bool */
+#define CSR_PSKEY_UART_DFU_CONFIG_RX_RATE_DELAY 0x041e /* uint16 */
+#define CSR_PSKEY_AMUX_AIO0 0x041f /* ana_amux_sel */
+#define CSR_PSKEY_AMUX_AIO1 0x0420 /* ana_amux_sel */
+#define CSR_PSKEY_AMUX_AIO2 0x0421 /* ana_amux_sel */
+#define CSR_PSKEY_AMUX_AIO3 0x0422 /* ana_amux_sel */
+#define CSR_PSKEY_LOCAL_NAME_SIMPLIFIED 0x0423 /* local_name_complete */
+#define CSR_PSKEY_EXTENDED_STUB 0x2001 /* uint16 */
+
+char *csr_builddeftostr(uint16_t def);
+char *csr_buildidtostr(uint16_t id);
+char *csr_chipvertostr(uint16_t ver, uint16_t rev);
+char *csr_pskeytostr(uint16_t pskey);
+char *csr_pskeytoval(uint16_t pskey);
+
+int csr_open_hci(char *device);
+int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length);
+int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length);
+void csr_close_hci(void);
+
+int csr_open_usb(char *device);
+int csr_read_usb(uint16_t varid, uint8_t *value, uint16_t length);
+int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length);
+void csr_close_usb(void);
+
+int csr_open_bcsp(char *device);
+int csr_read_bcsp(uint16_t varid, uint8_t *value, uint16_t length);
+int csr_write_bcsp(uint16_t varid, uint8_t *value, uint16_t length);
+void csr_close_bcsp(void);
+
+int csr_open_h4(char *device);
+int csr_read_h4(uint16_t varid, uint8_t *value, uint16_t length);
+int csr_write_h4(uint16_t varid, uint8_t *value, uint16_t length);
+void csr_close_h4(void);
+
+int csr_open_3wire(char *device);
+int csr_read_3wire(uint16_t varid, uint8_t *value, uint16_t length);
+int csr_write_3wire(uint16_t varid, uint8_t *value, uint16_t length);
+void csr_close_3wire(void);
+
+int csr_write_varid_valueless(int dd, uint16_t seqnum, uint16_t varid);
+int csr_write_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length);
+int csr_read_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length);
+int csr_read_varid_uint16(int dd, uint16_t seqnum, uint16_t varid, uint16_t *value);
+int csr_read_varid_uint32(int dd, uint16_t seqnum, uint16_t varid, uint32_t *value);
+int csr_read_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length);
+int csr_write_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length);
+int csr_read_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t *value);
+int csr_write_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t value);
+int csr_read_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t *value);
+int csr_write_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t value);
+
+int psr_put(uint16_t pskey, uint8_t *value, uint16_t size);
+int psr_get(uint16_t *pskey, uint8_t *value, uint16_t *size);
+int psr_read(const char *filename);
+int psr_print(void);
diff --git a/utils/tools/csr_3wire.c b/utils/tools/csr_3wire.c
new file mode 100644
index 00000000..ed2064cd
--- /dev/null
+++ b/utils/tools/csr_3wire.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 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 <stdint.h>
+
+static uint16_t seqnum = 0x0000;
+
+int csr_open_3wire(char *device)
+{
+ fprintf(stderr, "Transport not implemented\n");
+
+ return -1;
+}
+
+static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ errno = EIO;
+
+ return -1;
+}
+
+int csr_read_3wire(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0000, seqnum++, varid, value, length);
+}
+
+int csr_write_3wire(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0002, seqnum++, varid, value, length);
+}
+
+void csr_close_3wire(void)
+{
+}
diff --git a/utils/tools/csr_bcsp.c b/utils/tools/csr_bcsp.c
new file mode 100644
index 00000000..0dc334cb
--- /dev/null
+++ b/utils/tools/csr_bcsp.c
@@ -0,0 +1,255 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <termios.h>
+
+#include "csr.h"
+#include "ubcsp.h"
+
+static uint16_t seqnum = 0x0000;
+
+static int fd = -1;
+
+static struct ubcsp_packet send_packet;
+static uint8_t send_buffer[512];
+
+static struct ubcsp_packet receive_packet;
+static uint8_t receive_buffer[512];
+
+int csr_open_bcsp(char *device)
+{
+ struct termios ti;
+ uint8_t delay, activity = 0x00;
+ int timeout = 0;
+
+ if (!device)
+ device = "/dev/ttyS0";
+
+ fd = open(device, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open serial port: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (tcgetattr(fd, &ti) < 0) {
+ fprintf(stderr, "Can't get port settings: %s (%d)\n",
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ cfmakeraw(&ti);
+
+ ti.c_cflag |= CLOCAL;
+ ti.c_cflag &= ~CRTSCTS;
+ ti.c_cflag |= PARENB;
+ ti.c_cflag &= ~PARODD;
+ ti.c_cflag &= ~CSIZE;
+ ti.c_cflag |= CS8;
+ ti.c_cflag &= ~CSTOPB;
+
+ ti.c_cc[VMIN] = 1;
+ ti.c_cc[VTIME] = 0;
+
+ cfsetospeed(&ti, B38400);
+
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ fprintf(stderr, "Can't change port settings: %s (%d)\n",
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) {
+ fprintf(stderr, "Can't set non blocking mode: %s (%d)\n",
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ memset(&send_packet, 0, sizeof(send_packet));
+ memset(&receive_packet, 0, sizeof(receive_packet));
+
+ ubcsp_initialize();
+
+ send_packet.length = 512;
+ send_packet.payload = send_buffer;
+
+ receive_packet.length = 512;
+ receive_packet.payload = receive_buffer;
+
+ ubcsp_receive_packet(&receive_packet);
+
+ while (1) {
+ delay = ubcsp_poll(&activity);
+
+ if (activity & UBCSP_PACKET_RECEIVED)
+ break;
+
+ if (delay) {
+ usleep(delay * 100);
+
+ if (timeout++ > 100) {
+ fprintf(stderr, "Initialization timed out\n");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void put_uart(uint8_t ch)
+{
+ if (write(fd, &ch, 1) < 0)
+ fprintf(stderr, "UART write error\n");
+}
+
+uint8_t get_uart(uint8_t *ch)
+{
+ int res = read(fd, ch, 1);
+ return res > 0 ? res : 0;
+}
+
+static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ unsigned char cp[254], rp[254];
+ uint8_t cmd[10];
+ uint16_t size;
+ uint8_t delay, activity = 0x00;
+ int timeout = 0, sent = 0;
+
+ size = (length < 8) ? 9 : ((length + 1) / 2) + 5;
+
+ cmd[0] = command & 0xff;
+ cmd[1] = command >> 8;
+ cmd[2] = size & 0xff;
+ cmd[3] = size >> 8;
+ cmd[4] = seqnum & 0xff;
+ cmd[5] = seqnum >> 8;
+ cmd[6] = varid & 0xff;
+ cmd[7] = varid >> 8;
+ cmd[8] = 0x00;
+ cmd[9] = 0x00;
+
+ memset(cp, 0, sizeof(cp));
+ cp[0] = 0x00;
+ cp[1] = 0xfc;
+ cp[2] = (size * 2) + 1;
+ cp[3] = 0xc2;
+ memcpy(cp + 4, cmd, sizeof(cmd));
+ memcpy(cp + 14, value, length);
+
+ receive_packet.length = 512;
+ ubcsp_receive_packet(&receive_packet);
+
+ send_packet.channel = 5;
+ send_packet.reliable = 1;
+ send_packet.length = (size * 2) + 4;
+ memcpy(send_packet.payload, cp, (size * 2) + 4);
+
+ ubcsp_send_packet(&send_packet);
+
+ while (1) {
+ delay = ubcsp_poll(&activity);
+
+ if (activity & UBCSP_PACKET_RECEIVED) {
+ if (sent && receive_packet.channel == 5 &&
+ receive_packet.payload[0] == 0xff) {
+ memcpy(rp, receive_packet.payload,
+ receive_packet.length);
+ break;
+ }
+
+ receive_packet.length = 512;
+ ubcsp_receive_packet(&receive_packet);
+ timeout = 0;
+ }
+
+ if (activity & UBCSP_PACKET_SENT) {
+ switch (varid) {
+ case CSR_VARID_COLD_RESET:
+ case CSR_VARID_WARM_RESET:
+ case CSR_VARID_COLD_HALT:
+ case CSR_VARID_WARM_HALT:
+ return 0;
+ }
+
+ sent = 1;
+ timeout = 0;
+ }
+
+ if (delay) {
+ usleep(delay * 100);
+
+ if (timeout++ > 100) {
+ fprintf(stderr, "Operation timed out\n");
+ return -1;
+ }
+ }
+ }
+
+ if (rp[0] != 0xff || rp[2] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[11] + (rp[12] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ memcpy(value, rp + 13, length);
+
+ return 0;
+}
+
+int csr_read_bcsp(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0000, seqnum++, varid, value, length);
+}
+
+int csr_write_bcsp(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0002, seqnum++, varid, value, length);
+}
+
+void csr_close_bcsp(void)
+{
+ close(fd);
+}
diff --git a/utils/tools/csr_h4.c b/utils/tools/csr_h4.c
new file mode 100644
index 00000000..27ea3e3c
--- /dev/null
+++ b/utils/tools/csr_h4.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <termios.h>
+
+#include "csr.h"
+
+static uint16_t seqnum = 0x0000;
+
+static int fd = -1;
+
+int csr_open_h4(char *device)
+{
+ struct termios ti;
+
+ if (!device)
+ device = "/dev/ttyS0";
+
+ fd = open(device, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open serial port: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (tcgetattr(fd, &ti) < 0) {
+ fprintf(stderr, "Can't get port settings: %s (%d)\n",
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ cfmakeraw(&ti);
+
+ ti.c_cflag |= CLOCAL;
+ ti.c_cflag |= CRTSCTS;
+
+ cfsetospeed(&ti, B38400);
+
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ fprintf(stderr, "Can't change port settings: %s (%d)\n",
+ strerror(errno), errno);
+ close(fd);
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ return 0;
+}
+
+static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ unsigned char cp[254], rp[254];
+ uint8_t cmd[10];
+ uint16_t size;
+ int len, offset = 3;
+
+ size = (length < 8) ? 9 : ((length + 1) / 2) + 5;
+
+ cmd[0] = command & 0xff;
+ cmd[1] = command >> 8;
+ cmd[2] = size & 0xff;
+ cmd[3] = size >> 8;
+ cmd[4] = seqnum & 0xff;
+ cmd[5] = seqnum >> 8;
+ cmd[6] = varid & 0xff;
+ cmd[7] = varid >> 8;
+ cmd[8] = 0x00;
+ cmd[9] = 0x00;
+
+ memset(cp, 0, sizeof(cp));
+ cp[0] = 0x01;
+ cp[1] = 0x00;
+ cp[2] = 0xfc;
+ cp[3] = (size * 2) + 1;
+ cp[4] = 0xc2;
+ memcpy(cp + 5, cmd, sizeof(cmd));
+ memcpy(cp + 15, value, length);
+
+ if (write(fd, cp, (size * 2) + 5) < 0)
+ return -1;
+
+ switch (varid) {
+ case CSR_VARID_COLD_RESET:
+ case CSR_VARID_WARM_RESET:
+ case CSR_VARID_COLD_HALT:
+ case CSR_VARID_WARM_HALT:
+ return 0;
+ }
+
+ do {
+ if (read(fd, rp, 1) < 1)
+ return -1;
+ } while (rp[0] != 0x04);
+
+ if (read(fd, rp + 1, 2) < 2)
+ return -1;
+
+ do {
+ len = read(fd, rp + offset, sizeof(rp) - offset);
+ offset += len;
+ } while (offset < rp[2] + 3);
+
+ if (rp[0] != 0x04 || rp[1] != 0xff || rp[3] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[12] + (rp[13] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ memcpy(value, rp + 14, length);
+
+ return 0;
+}
+
+int csr_read_h4(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0000, seqnum++, varid, value, length);
+}
+
+int csr_write_h4(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0002, seqnum++, varid, value, length);
+}
+
+void csr_close_h4(void)
+{
+ close(fd);
+}
diff --git a/utils/tools/csr_hci.c b/utils/tools/csr_hci.c
new file mode 100644
index 00000000..454cbfb2
--- /dev/null
+++ b/utils/tools/csr_hci.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "csr.h"
+
+static uint16_t seqnum = 0x0000;
+
+static int dd = -1;
+
+int csr_open_hci(char *device)
+{
+ struct hci_dev_info di;
+ struct hci_version ver;
+ int dev = 0;
+
+ if (device) {
+ dev = hci_devid(device);
+ if (dev < 0) {
+ fprintf(stderr, "Device not available\n");
+ return -1;
+ }
+ }
+
+ dd = hci_open_dev(dev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ return -1;
+ }
+
+ if (hci_devinfo(dev, &di) < 0) {
+ fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ return -1;
+ }
+
+ if (hci_read_local_version(dd, &ver, 1000) < 0) {
+ fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n",
+ dev, strerror(errno), errno);
+ hci_close_dev(dd);
+ return -1;
+ }
+
+ if (ver.manufacturer != 10) {
+ fprintf(stderr, "Unsupported manufacturer\n");
+ hci_close_dev(dd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ unsigned char cp[254], rp[254];
+ struct hci_request rq;
+ uint8_t cmd[10];
+ uint16_t size;
+
+ size = (length < 8) ? 9 : ((length + 1) / 2) + 5;
+
+ cmd[0] = command & 0xff;
+ cmd[1] = command >> 8;
+ cmd[2] = size & 0xff;
+ cmd[3] = size >> 8;
+ cmd[4] = seqnum & 0xff;
+ cmd[5] = seqnum >> 8;
+ cmd[6] = varid & 0xff;
+ cmd[7] = varid >> 8;
+ cmd[8] = 0x00;
+ cmd[9] = 0x00;
+
+ memset(cp, 0, sizeof(cp));
+ cp[0] = 0xc2;
+ memcpy(cp + 1, cmd, sizeof(cmd));
+ memcpy(cp + 11, value, length);
+
+ switch (varid) {
+ case CSR_VARID_COLD_RESET:
+ case CSR_VARID_WARM_RESET:
+ case CSR_VARID_COLD_HALT:
+ case CSR_VARID_WARM_HALT:
+ return hci_send_cmd(dd, OGF_VENDOR_CMD, 0x00, (size * 2) + 1, cp);
+ }
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x00;
+ rq.event = EVT_VENDOR;
+ rq.cparam = cp;
+ rq.clen = (size * 2) + 1;
+ rq.rparam = rp;
+ rq.rlen = sizeof(rp);
+
+ if (hci_send_req(dd, &rq, 2000) < 0)
+ return -1;
+
+ if (rp[0] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[9] + (rp[10] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ memcpy(value, rp + 11, length);
+
+ return 0;
+}
+
+int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0000, seqnum++, varid, value, length);
+}
+
+int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0002, seqnum++, varid, value, length);
+}
+
+void csr_close_hci(void)
+{
+ hci_close_dev(dd);
+}
diff --git a/utils/tools/csr_usb.c b/utils/tools/csr_usb.c
new file mode 100644
index 00000000..b7703dcf
--- /dev/null
+++ b/utils/tools/csr_usb.c
@@ -0,0 +1,180 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <usb.h>
+
+#include "csr.h"
+
+#ifdef NEED_USB_GET_BUSSES
+static inline struct usb_bus *usb_get_busses(void)
+{
+ return usb_busses;
+}
+#endif
+
+#ifdef NEED_USB_INTERRUPT_READ
+static inline int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+ return usb_bulk_read(dev, ep, bytes, size, timeout);
+}
+#endif
+
+#ifndef USB_DIR_OUT
+#define USB_DIR_OUT 0x00
+#endif
+
+static uint16_t seqnum = 0x0000;
+
+static struct usb_dev_handle *udev = NULL;
+
+int csr_open_usb(char *device)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_get_busses(); bus; bus = bus->next) {
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ continue;
+
+ if (dev->descriptor.idVendor != 0x0a12 ||
+ dev->descriptor.idProduct != 0x0001)
+ continue;
+
+ goto found;
+ }
+ }
+
+ fprintf(stderr, "Device not available\n");
+
+ return -1;
+
+found:
+ udev = usb_open(dev);
+ if (!udev) {
+ fprintf(stderr, "Can't open device: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ if (usb_claim_interface(udev, 0) < 0) {
+ fprintf(stderr, "Can't claim interface: %s (%d)\n",
+ strerror(errno), errno);
+ usb_close(udev);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+{
+ unsigned char cp[254], rp[254];
+ uint8_t cmd[10];
+ uint16_t size;
+ int len, offset = 0;
+
+ size = (length < 8) ? 9 : ((length + 1) / 2) + 5;
+
+ cmd[0] = command & 0xff;
+ cmd[1] = command >> 8;
+ cmd[2] = size & 0xff;
+ cmd[3] = size >> 8;
+ cmd[4] = seqnum & 0xff;
+ cmd[5] = seqnum >> 8;
+ cmd[6] = varid & 0xff;
+ cmd[7] = varid >> 8;
+ cmd[8] = 0x00;
+ cmd[9] = 0x00;
+
+ memset(cp, 0, sizeof(cp));
+ cp[0] = 0x00;
+ cp[1] = 0xfc;
+ cp[2] = (size * 2) + 1;
+ cp[3] = 0xc2;
+ memcpy(cp + 4, cmd, sizeof(cmd));
+ memcpy(cp + 14, value, length);
+
+ usb_interrupt_read(udev, 0x81, (void *) rp, sizeof(rp), 2);
+
+ if (usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_DEVICE,
+ 0, 0, 0, (void *) cp, (size * 2) + 4, 1000) < 0)
+ return -1;
+
+ switch (varid) {
+ case CSR_VARID_COLD_RESET:
+ case CSR_VARID_WARM_RESET:
+ case CSR_VARID_COLD_HALT:
+ case CSR_VARID_WARM_HALT:
+ return 0;
+ }
+
+ do {
+ len = usb_interrupt_read(udev, 0x81,
+ (void *) (rp + offset), sizeof(rp) - offset, 10);
+ offset += len;
+ } while (len > 0);
+
+ if (rp[0] != 0xff || rp[2] != 0xc2) {
+ errno = EIO;
+ return -1;
+ }
+
+ if ((rp[11] + (rp[12] << 8)) != 0) {
+ errno = ENXIO;
+ return -1;
+ }
+
+ memcpy(value, rp + 13, length);
+
+ return 0;
+}
+
+int csr_read_usb(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0000, seqnum++, varid, value, length);
+}
+
+int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length)
+{
+ return do_command(0x0002, seqnum++, varid, value, length);
+}
+
+void csr_close_usb(void)
+{
+ usb_release_interface(udev, 0);
+ usb_close(udev);
+}
diff --git a/utils/tools/dfu.c b/utils/tools/dfu.c
new file mode 100644
index 00000000..069cbb89
--- /dev/null
+++ b/utils/tools/dfu.c
@@ -0,0 +1,168 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <usb.h>
+
+#include "dfu.h"
+
+#ifndef USB_DIR_OUT
+#define USB_DIR_OUT 0x00
+#endif
+
+#ifndef USB_DIR_IN
+#define USB_DIR_IN 0x80
+#endif
+
+#ifndef USB_DT_DFU
+#define USB_DT_DFU 0x21
+#endif
+
+#define DFU_PACKETSIZE 0x03ff /* CSR default value: 1023 */
+#define DFU_TIMEOUT 10000
+
+static uint32_t dfu_crc32_table[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+uint32_t crc32_init(void)
+{
+ return 0xffffffff;
+}
+
+uint32_t crc32_byte(uint32_t accum, uint8_t delta)
+{
+ return dfu_crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8);
+}
+
+int dfu_detach(struct usb_dev_handle *udev, int intf)
+{
+ if (!udev)
+ return -EIO;
+
+ return usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_DETACH, 0x1388, intf, NULL, 0, DFU_TIMEOUT);
+}
+
+int dfu_upload(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size)
+{
+ if (!udev)
+ return -EIO;
+
+ return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ DFU_UPLOAD, block, intf, buffer, size, DFU_TIMEOUT);
+}
+
+int dfu_download(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size)
+{
+ if (!udev)
+ return -EIO;
+
+ return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
+ DFU_DNLOAD, block, intf, buffer, size, DFU_TIMEOUT);
+}
+
+int dfu_get_status(struct usb_dev_handle *udev, int intf, struct dfu_status *status)
+{
+ if (!udev || !status)
+ return -EIO;
+
+ return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ DFU_GETSTATUS, 0, intf, (char *) status, DFU_STATUS_SIZE, DFU_TIMEOUT);
+}
+
+int dfu_clear_status(struct usb_dev_handle *udev, int intf)
+{
+ if (!udev)
+ return -EIO;
+
+ return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
+ DFU_CLRSTATUS, 0, intf, NULL, 0, DFU_TIMEOUT);
+}
+
+int dfu_get_state(struct usb_dev_handle *udev, int intf, uint8_t *state)
+{
+ if (!udev || !state)
+ return -EIO;
+
+ return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ DFU_GETSTATE, 0, intf, (char *) state, 1, DFU_TIMEOUT);
+}
+
+int dfu_abort(struct usb_dev_handle *udev, int intf)
+{
+ if (!udev)
+ return -EIO;
+
+ return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
+ DFU_ABORT, 0, intf, NULL, 0, DFU_TIMEOUT);
+}
diff --git a/utils/tools/dfu.h b/utils/tools/dfu.h
new file mode 100644
index 00000000..39d25250
--- /dev/null
+++ b/utils/tools/dfu.h
@@ -0,0 +1,107 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+
+/* CRC interface */
+uint32_t crc32_init(void);
+uint32_t crc32_byte(uint32_t accum, uint8_t delta);
+
+/* DFU descriptor */
+struct usb_dfu_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int8_t bmAttributes;
+ u_int16_t wDetachTimeout;
+ u_int16_t wTransferSize;
+};
+
+/* DFU commands */
+#define DFU_DETACH 0
+#define DFU_DNLOAD 1
+#define DFU_UPLOAD 2
+#define DFU_GETSTATUS 3
+#define DFU_CLRSTATUS 4
+#define DFU_GETSTATE 5
+#define DFU_ABORT 6
+
+/* DFU status */
+struct dfu_status {
+ uint8_t bStatus;
+ uint8_t bwPollTimeout[3];
+ uint8_t bState;
+ uint8_t iString;
+} __attribute__ ((packed));
+#define DFU_STATUS_SIZE 6
+
+/* DFU status */
+#define DFU_OK 0x00
+#define DFU_ERR_TARGET 0x01
+#define DFU_ERR_FILE 0x02
+#define DFU_ERR_WRITE 0x03
+#define DFU_ERR_ERASE 0x04
+#define DFU_ERR_CHECK_ERASED 0x05
+#define DFU_ERR_PROG 0x06
+#define DFU_ERR_VERIFY 0x07
+#define DFU_ERR_ADDRESS 0x08
+#define DFU_ERR_NOTDONE 0x09
+#define DFU_ERR_FIRMWARE 0x0a
+#define DFU_ERR_VENDOR 0x0b
+#define DFU_ERR_USBR 0x0c
+#define DFU_ERR_POR 0x0d
+#define DFU_ERR_UNKNOWN 0x0e
+#define DFU_ERR_STALLEDPKT 0x0f
+
+/* DFU state */
+#define DFU_STATE_APP_IDLE 0
+#define DFU_STATE_APP_DETACH 1
+#define DFU_STATE_DFU_IDLE 2
+#define DFU_STATE_DFU_DNLOAD_SYNC 3
+#define DFU_STATE_DFU_DNLOAD_BUSY 4
+#define DFU_STATE_DFU_DNLOAD_IDLE 5
+#define DFU_STATE_DFU_MANIFEST_SYNC 6
+#define DFU_STATE_DFU_MANIFEST 7
+#define DFU_STATE_MANIFEST_WAIT_RESET 8
+#define DFU_STATE_UPLOAD_IDLE 9
+#define DFU_STATE_ERROR 10
+
+/* DFU suffix */
+struct dfu_suffix {
+ uint16_t bcdDevice;
+ uint16_t idProduct;
+ uint16_t idVendor;
+ uint16_t bcdDFU;
+ uint8_t ucDfuSignature[3];
+ uint8_t bLength;
+ uint32_t dwCRC;
+} __attribute__ ((packed));
+#define DFU_SUFFIX_SIZE 16
+
+/* DFU interface */
+int dfu_detach(struct usb_dev_handle *udev, int intf);
+int dfu_upload(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size);
+int dfu_download(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size);
+int dfu_get_status(struct usb_dev_handle *udev, int intf, struct dfu_status *status);
+int dfu_clear_status(struct usb_dev_handle *udev, int intf);
+int dfu_get_state(struct usb_dev_handle *udev, int intf, uint8_t *state);
+int dfu_abort(struct usb_dev_handle *udev, int intf);
diff --git a/utils/tools/dfubabel.1 b/utils/tools/dfubabel.1
new file mode 100644
index 00000000..5e0f805f
--- /dev/null
+++ b/utils/tools/dfubabel.1
@@ -0,0 +1,38 @@
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.TH DFUBABEL 8 "JUNE 6, 2005" "" ""
+
+.SH NAME
+dfubabel \- Babel DFU mode switching utility
+.SH SYNOPSIS
+.BR "dfubabel
+[
+.I options
+]
+.SH DESCRIPTION
+.B dfubabel
+is used to switch Babel devices into DFU mode.
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible options.
+.TP
+.BI -q
+Don't display any messages.
+.SH AUTHOR
+Written by Marcel Holtmann <marcel@holtmann.org>.
+.br
diff --git a/utils/tools/dfubabel.c b/utils/tools/dfubabel.c
new file mode 100644
index 00000000..78dfa9f9
--- /dev/null
+++ b/utils/tools/dfubabel.c
@@ -0,0 +1,211 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <usb.h>
+
+#ifdef NEED_USB_GET_BUSSES
+static inline struct usb_bus *usb_get_busses(void)
+{
+ return usb_busses;
+}
+#endif
+
+struct device_info;
+
+struct device_id {
+ uint16_t vendor;
+ uint16_t product;
+ int (*func)(struct device_info *dev, int argc, char *argv[]);
+};
+
+struct device_info {
+ struct usb_device *dev;
+ struct device_id *id;
+};
+
+static int switch_babel(struct device_info *devinfo, int argc, char *argv[])
+{
+ char buf[3];
+ struct usb_dev_handle *udev;
+ int err;
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0] = 0x00;
+ buf[1] = 0x06;
+ buf[2] = 0x00;
+
+ udev = usb_open(devinfo->dev);
+ if (!udev)
+ return -errno;
+
+ if (usb_claim_interface(udev, 0) < 0) {
+ err = -errno;
+ usb_close(udev);
+ return err;
+ }
+
+ err = usb_bulk_write(udev, 0x02, buf, sizeof(buf), 10000);
+
+ if (err == 0) {
+ err = -1;
+ errno = EALREADY;
+ } else {
+ if (errno == ETIMEDOUT)
+ err = 0;
+ }
+
+ usb_release_interface(udev, 0);
+ usb_close(udev);
+
+ return err;
+}
+
+static struct device_id device_list[] = {
+ { 0x0a12, 0x0042, switch_babel },
+ { -1 }
+};
+
+static struct device_id *match_device(uint16_t vendor, uint16_t product)
+{
+ int i;
+
+ for (i = 0; device_list[i].func; i++) {
+ if (vendor == device_list[i].vendor &&
+ product == device_list[i].product)
+ return &device_list[i];
+ }
+
+ return NULL;
+}
+
+static int find_devices(struct device_info *devinfo, size_t size)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ struct device_id *id;
+ int count = 0;
+
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_get_busses(); bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next) {
+ id = match_device(dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ if (!id)
+ continue;
+
+ if (count < size) {
+ devinfo[count].dev = dev;
+ devinfo[count].id = id;
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static void usage(void)
+{
+ printf("dfubabel - Babel DFU mode switching utility\n\n");
+
+ printf("Usage:\n"
+ "\tdfubabel [options]\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-h, --help Display help\n"
+ "\t-q, --quiet Don't display any messages\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "quiet", 0, 0, 'q' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct device_info dev[16];
+ int i, opt, num, quiet = 0;
+
+ while ((opt = getopt_long(argc, argv, "+qh", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'q':
+ quiet = 1;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ usb_init();
+
+ num = find_devices(dev, sizeof(dev) / sizeof(dev[0]));
+ if (num <= 0) {
+ if (!quiet)
+ fprintf(stderr, "No Babel devices found\n");
+ exit(1);
+ }
+
+ for (i = 0; i < num; i++) {
+ struct device_id *id = dev[i].id;
+ int err;
+
+ if (!quiet)
+ printf("Switching device %04x:%04x ",
+ id->vendor, id->product);
+ fflush(stdout);
+
+ err = id->func(&dev[i], argc, argv);
+ if (err < 0) {
+ if (!quiet)
+ printf("failed (%s)\n", strerror(-err));
+ } else {
+ if (!quiet)
+ printf("was successful\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/utils/tools/dfutool.1 b/utils/tools/dfutool.1
new file mode 100644
index 00000000..78b1fe7f
--- /dev/null
+++ b/utils/tools/dfutool.1
@@ -0,0 +1,53 @@
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.TH DFUTOOL 1 "APRIL 21, 2005" "" ""
+
+.SH NAME
+dfutool \- Device Firmware Upgrade utility
+.SH SYNOPSIS
+.BR "dfutool
+[
+.I options
+] <
+.I command
+>
+.SH DESCRIPTION
+.B dfutool
+is used to verify, archive and upgrade firmware files.
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible commands.
+.TP
+.BI -d " <device>"
+The command specifies the device to use.
+.SH COMMANDS
+.TP
+.BI verify " <dfu-file>"
+Display information about the firmware file.
+.TP
+.BI modify " <dfu-file>"
+Change DFU specific values in the firmware file.
+.TP
+.BI upgrade " <dfu-file>"
+Upgrade the device with a new firmware.
+.TP
+.BI archive " <dfu-file>"
+Archive the current firmware of the device.
+.SH AUTHOR
+Written by Marcel Holtmann <marcel@holtmann.org>.
+.br
diff --git a/utils/tools/dfutool.c b/utils/tools/dfutool.c
new file mode 100644
index 00000000..246d92a4
--- /dev/null
+++ b/utils/tools/dfutool.c
@@ -0,0 +1,788 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <libgen.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <usb.h>
+
+#include "dfu.h"
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(d) (d)
+#define cpu_to_le32(d) (d)
+#define le16_to_cpu(d) (d)
+#define le32_to_cpu(d) (d)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(d) bswap_16(d)
+#define cpu_to_le32(d) bswap_32(d)
+#define le16_to_cpu(d) bswap_16(d)
+#define le32_to_cpu(d) bswap_32(d)
+#else
+#error "Unknown byte order"
+#endif
+
+#ifdef NEED_USB_GET_BUSSES
+static inline struct usb_bus *usb_get_busses(void)
+{
+ return usb_busses;
+}
+#endif
+
+#ifndef USB_CLASS_WIRELESS
+#define USB_CLASS_WIRELESS 0xe0
+#endif
+
+#ifndef USB_CLASS_APPLICATION
+#define USB_CLASS_APPLICATION 0xfe
+#endif
+
+static int get_interface_number(struct usb_device *dev)
+{
+ int c, i, a;
+
+ for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+ struct usb_config_descriptor *config = &dev->config[c];
+
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ struct usb_interface *interface = &config->interface[i];
+
+ for (a = 0; a < interface->num_altsetting; a++) {
+ struct usb_interface_descriptor *desc = &interface->altsetting[a];
+
+ if (desc->bInterfaceClass != USB_CLASS_APPLICATION)
+ continue;
+ if (desc->bInterfaceSubClass != 0x01)
+ continue;
+ if (desc->bInterfaceProtocol != 0x00)
+ continue;
+
+ return desc->bInterfaceNumber;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static void print_device(struct usb_device *dev)
+{
+ printf("Bus %s Device %s: ID %04x:%04x Interface %d%s\n",
+ dev->bus->dirname, dev->filename,
+ dev->descriptor.idVendor, dev->descriptor.idProduct,
+ get_interface_number(dev),
+ dev->descriptor.bDeviceClass == USB_CLASS_APPLICATION ? " (DFU mode)" : "");
+}
+
+static struct usb_dev_handle *open_device(char *device, struct dfu_suffix *suffix)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev, *dfu_dev[10];
+ struct usb_dev_handle *udev;
+ struct dfu_status status;
+ char str[8];
+ int i, intf, sel, num = 0, try = 5, bus_id = -1, dev_id = -1;
+
+ printf("Scanning USB busses ... ");
+ fflush(stdout);
+
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_get_busses(); bus; bus = bus->next) {
+ if (bus_id > 0) {
+ snprintf(str, sizeof(str) - 1, "%03i", bus_id);
+ if (strcmp(str, bus->dirname))
+ continue;
+ }
+
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if (bus_id > 0 && dev_id > 0) {
+ snprintf(str, sizeof(str) - 1, "%03i", dev_id);
+ if (strcmp(str, dev->filename))
+ continue;
+ }
+
+ if (dev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ continue;
+
+ if (num > 9 || get_interface_number(dev) < 0)
+ continue;
+
+ dfu_dev[num++] = dev;
+ }
+ }
+
+ if (num < 1) {
+ printf("\rCan't find any DFU devices\n");
+ return NULL;
+ }
+
+ printf("\rAvailable devices with DFU support:\n\n");
+ for (i = 0; i < num; i++) {
+ printf("\t%2d) ", i + 1);
+ print_device(dfu_dev[i]);
+ }
+ printf("\n");
+
+ do {
+ printf("\rSelect device (abort with 0): ");
+ fflush(stdout);
+ memset(str, 0, sizeof(str));
+ if (!fgets(str, sizeof(str) - 1, stdin))
+ continue;
+ sel = atoi(str);
+ } while (!isdigit(str[0]) || sel < 0 || sel > num );
+
+ if (sel < 1)
+ return NULL;
+
+ sel--;
+ intf = get_interface_number(dfu_dev[sel]);
+ printf("\n");
+
+ udev = usb_open(dfu_dev[sel]);
+ if (!udev) {
+ printf("Can't open device: %s (%d)\n", strerror(errno), errno);
+ return NULL;
+ }
+
+ if (usb_claim_interface(udev, intf) < 0) {
+ printf("Can't claim interface: %s (%d)\n", strerror(errno), errno);
+ usb_close(udev);
+ return NULL;
+ }
+
+ if (dfu_get_status(udev, intf, &status) < 0) {
+ printf("Can't get status: %s (%d)\n", strerror(errno), errno);
+ goto error;
+ }
+
+ if (status.bState == DFU_STATE_ERROR) {
+ if (dfu_clear_status(udev, intf) < 0) {
+ printf("Can't clear status: %s (%d)\n", strerror(errno), errno);
+ goto error;
+ }
+ if (dfu_abort(udev, intf) < 0) {
+ printf("Can't abort previous action: %s (%d)\n", strerror(errno), errno);
+ goto error;
+ }
+ if (dfu_get_status(udev, intf, &status) < 0) {
+ printf("Can't get status: %s (%d)\n", strerror(errno), errno);
+ goto error;
+ }
+ }
+
+ if (status.bState == DFU_STATE_DFU_IDLE) {
+ if (suffix) {
+ suffix->idVendor = cpu_to_le16(0x0000);
+ suffix->idProduct = cpu_to_le16(0x0000);
+ suffix->bcdDevice = cpu_to_le16(0x0000);
+ }
+ return udev;
+ }
+
+ if (status.bState != DFU_STATE_APP_IDLE) {
+ printf("Device is not idle, can't detach it (state %d)\n", status.bState);
+ goto error;
+ }
+
+ printf("Switching device into DFU mode ... ");
+ fflush(stdout);
+
+ if (suffix) {
+ suffix->idVendor = cpu_to_le16(dfu_dev[sel]->descriptor.idVendor);
+ suffix->idProduct = cpu_to_le16(dfu_dev[sel]->descriptor.idProduct);
+ suffix->bcdDevice = cpu_to_le16(dfu_dev[sel]->descriptor.bcdDevice);
+ }
+
+ if (dfu_detach(udev, intf) < 0) {
+ printf("\rCan't detach device: %s (%d)\n", strerror(errno), errno);
+ goto error;
+ }
+
+ if (dfu_get_status(udev, intf, &status) < 0) {
+ printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
+ goto error;
+ }
+
+ if (status.bState != DFU_STATE_APP_DETACH) {
+ printf("\rDevice is not in detach mode, try again\n");
+ goto error;
+ }
+
+ usb_release_interface(udev, intf);
+ usb_reset(udev);
+ usb_close(udev);
+
+ bus = dfu_dev[sel]->bus;
+ num = 0;
+
+ while (num != 1 && try-- > 0) {
+ sleep(1);
+ usb_find_devices();
+
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.bDeviceClass != USB_CLASS_APPLICATION)
+ continue;
+
+ if (suffix && dev->descriptor.idVendor != le16_to_cpu(suffix->idVendor))
+ continue;
+
+ if (num > 9 || get_interface_number(dev) != 0)
+ continue;
+
+ dfu_dev[num++] = dev;
+ }
+ }
+
+ if (num != 1) {
+ printf("\rCan't identify device with DFU mode\n");
+ goto error;
+ }
+
+ printf("\r");
+
+ intf = 0;
+
+ udev = usb_open(dfu_dev[0]);
+ if (!udev) {
+ printf("Can't open device: %s (%d)\n", strerror(errno), errno);
+ return NULL;
+ }
+
+ if (usb_claim_interface(udev, intf) < 0) {
+ printf("Can't claim interface: %s (%d)\n", strerror(errno), errno);
+ usb_close(udev);
+ return NULL;
+ }
+
+ if (dfu_get_status(udev, intf, &status) < 0) {
+ printf("Can't get status: %s (%d)\n", strerror(errno), errno);
+ goto error;
+ }
+
+ if (status.bState != DFU_STATE_DFU_IDLE) {
+ printf("Device is not in DFU mode, can't use it\n");
+ goto error;
+ }
+
+ return udev;
+
+error:
+ usb_release_interface(udev, intf);
+ usb_close(udev);
+ return NULL;
+}
+
+static void usage(void);
+
+static void cmd_verify(char *device, int argc, char **argv)
+{
+ struct stat st;
+ struct dfu_suffix *suffix;
+ uint32_t crc;
+ uint16_t bcd;
+ char str[16];
+ unsigned char *buf;
+ unsigned long size;
+ char *filename;
+ int i, fd, len;
+
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
+
+ filename = argv[1];
+
+ if (stat(filename, &st) < 0) {
+ perror("Can't access firmware");
+ exit(1);
+ }
+
+ size = st.st_size;
+
+ if (!(buf = malloc(size))) {
+ perror("Unable to allocate file buffer");
+ exit(1);
+ }
+
+ if ((fd = open(filename, O_RDONLY)) < 0) {
+ perror("Can't open firmware");
+ free(buf);
+ exit(1);
+ }
+
+ if (read(fd, buf, size) < size) {
+ perror("Can't load firmware");
+ free(buf);
+ close(fd);
+ exit(1);
+ }
+
+ printf("Filename\t%s\n", basename(filename));
+ printf("Filesize\t%ld\n", size);
+
+ crc = crc32_init();
+ for (i = 0; i < size - 4; i++)
+ crc = crc32_byte(crc, buf[i]);
+ printf("Checksum\t%08x\n", crc);
+
+ printf("\n");
+ len = buf[size - 5];
+ printf("DFU suffix\t");
+ for (i = 0; i < len; i++) {
+ printf("%02x ", buf[size - len + i]);
+ }
+ printf("\n\n");
+
+ suffix = (struct dfu_suffix *) (buf + size - DFU_SUFFIX_SIZE);
+
+ printf("idVendor\t%04x\n", le16_to_cpu(suffix->idVendor));
+ printf("idProduct\t%04x\n", le16_to_cpu(suffix->idProduct));
+ printf("bcdDevice\t%x\n", le16_to_cpu(suffix->bcdDevice));
+
+ printf("\n");
+
+ bcd = le16_to_cpu(suffix->bcdDFU);
+
+ printf("bcdDFU\t\t%x.%x\n", bcd >> 8, bcd & 0xff);
+ printf("ucDfuSignature\t%c%c%c\n", suffix->ucDfuSignature[2],
+ suffix->ucDfuSignature[1], suffix->ucDfuSignature[0]);
+ printf("bLength\t\t%d\n", suffix->bLength);
+ printf("dwCRC\t\t%08x\n", le32_to_cpu(suffix->dwCRC));
+ printf("\n");
+
+ memset(str, 0, sizeof(str));
+ memcpy(str, buf, 8);
+
+ if (!strcmp(str, "CSR-dfu1") || !strcmp(str, "CSR-dfu2")) {
+ crc = crc32_init();
+ for (i = 0; i < size - DFU_SUFFIX_SIZE; i++)
+ crc = crc32_byte(crc, buf[i]);
+
+ printf("Firmware type\t%s\n", str);
+ printf("Firmware check\t%s checksum\n", crc == 0 ? "valid" : "corrupt");
+ printf("\n");
+ }
+
+ free(buf);
+
+ close(fd);
+}
+
+static void cmd_modify(char *device, int argc, char **argv)
+{
+}
+
+static void cmd_upgrade(char *device, int argc, char **argv)
+{
+ struct usb_dev_handle *udev;
+ struct dfu_status status;
+ struct dfu_suffix suffix;
+ struct stat st;
+ char *buf;
+ unsigned long filesize, count, timeout = 0;
+ char *filename;
+ uint32_t crc, dwCRC;
+ int fd, i, block, len, size, sent = 0, try = 10;
+
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
+
+ filename = argv[1];
+
+ if (stat(filename, &st) < 0) {
+ perror("Can't access firmware");
+ exit(1);
+ }
+
+ filesize = st.st_size;
+
+ if (!(buf = malloc(filesize))) {
+ perror("Unable to allocate file buffer");
+ exit(1);
+ }
+
+ if ((fd = open(filename, O_RDONLY)) < 0) {
+ perror("Can't open firmware");
+ free(buf);
+ exit(1);
+ }
+
+ if (read(fd, buf, filesize) < filesize) {
+ perror("Can't load firmware");
+ free(buf);
+ close(fd);
+ exit(1);
+ }
+
+ memcpy(&suffix, buf + filesize - DFU_SUFFIX_SIZE, sizeof(suffix));
+ dwCRC = le32_to_cpu(suffix.dwCRC);
+
+ printf("Filename\t%s\n", basename(filename));
+ printf("Filesize\t%ld\n", filesize);
+
+ crc = crc32_init();
+ for (i = 0; i < filesize - 4; i++)
+ crc = crc32_byte(crc, buf[i]);
+
+ printf("Checksum\t%08x (%s)\n", crc,
+ crc == dwCRC ? "valid" : "corrupt");
+
+ if (crc != dwCRC) {
+ free(buf);
+ close(fd);
+ exit(1);
+ }
+
+ printf("\n");
+
+ udev = open_device(device, &suffix);
+ if (!udev)
+ exit(1);
+
+ printf("\r" " " " " " " " " " ");
+ printf("\rFirmware download ... ");
+ fflush(stdout);
+
+ count = filesize - DFU_SUFFIX_SIZE;
+ block = 0;
+
+ while (count) {
+ size = (count > 1023) ? 1023 : count;
+
+ if (dfu_get_status(udev, 0, &status) < 0) {
+ if (try-- > 0) {
+ sleep(1);
+ continue;
+ }
+ printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+
+ if (status.bStatus != DFU_OK) {
+ if (try-- > 0) {
+ dfu_clear_status(udev, 0);
+ sleep(1);
+ continue;
+ }
+ printf("\rFirmware download ... aborting (status %d state %d)\n",
+ status.bStatus, status.bState);
+ goto done;
+ }
+
+ if (status.bState != DFU_STATE_DFU_IDLE &&
+ status.bState != DFU_STATE_DFU_DNLOAD_IDLE) {
+ sleep(1);
+ continue;
+ }
+
+ timeout = (status.bwPollTimeout[2] << 16) |
+ (status.bwPollTimeout[1] << 8) |
+ status.bwPollTimeout[0];
+
+ usleep(timeout * 1000);
+
+ len = dfu_download(udev, 0, block, buf + sent, size);
+ if (len < 0) {
+ if (try-- > 0) {
+ sleep(1);
+ continue;
+ }
+ printf("\rCan't upload next block: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+
+ printf("\rFirmware download ... %d bytes ", block * 1023 + len);
+ fflush(stdout);
+
+ sent += len;
+ count -= len;
+ block++;
+ }
+
+ printf("\r" " " " " " " " " " ");
+ printf("\rFinishing firmware download ... ");
+ fflush(stdout);
+
+ sleep(1);
+
+ if (dfu_get_status(udev, 0, &status) < 0) {
+ printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+
+ timeout = (status.bwPollTimeout[2] << 16) |
+ (status.bwPollTimeout[1] << 8) |
+ status.bwPollTimeout[0];
+
+ usleep(timeout * 1000);
+
+ if (count == 0) {
+ len = dfu_download(udev, 0, block, NULL, 0);
+ if (len < 0) {
+ printf("\rCan't send final block: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+ }
+
+ printf("\r" " " " " " " " " " ");
+ printf("\rWaiting for device ... ");
+ fflush(stdout);
+
+ sleep(10);
+
+ printf("\n");
+
+done:
+ free(buf);
+ close(fd);
+
+ usb_release_interface(udev, 0);
+ usb_reset(udev);
+ usb_close(udev);
+}
+
+static void cmd_archive(char *device, int argc, char **argv)
+{
+ struct usb_dev_handle *udev;
+ struct dfu_status status;
+ struct dfu_suffix suffix;
+ char buf[2048];
+ unsigned long timeout = 0;
+ char *filename;
+ uint32_t crc;
+ int fd, i, n, len, try = 8;
+
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
+
+ filename = argv[1];
+
+ udev = open_device(device, &suffix);
+ if (!udev)
+ exit(1);
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) {
+ printf("Can't open firmware file: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+
+ printf("\r" " " " " " " " " " ");
+ printf("\rFirmware upload ... ");
+ fflush(stdout);
+
+ crc = crc32_init();
+ n = 0;
+ while (1) {
+ if (dfu_get_status(udev, 0, &status) < 0) {
+ if (try-- > 0) {
+ sleep(1);
+ continue;
+ }
+ printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+
+ if (status.bStatus != DFU_OK) {
+ if (try-- > 0) {
+ dfu_clear_status(udev, 0);
+ sleep(1);
+ continue;
+ }
+ printf("\rFirmware upload ... aborting (status %d state %d)\n",
+ status.bStatus, status.bState);
+ goto done;
+ }
+
+ if (status.bState != DFU_STATE_DFU_IDLE &&
+ status.bState != DFU_STATE_UPLOAD_IDLE) {
+ sleep(1);
+ continue;
+ }
+
+ timeout = (status.bwPollTimeout[2] << 16) |
+ (status.bwPollTimeout[1] << 8) |
+ status.bwPollTimeout[0];
+
+ usleep(timeout * 1000);
+
+ len = dfu_upload(udev, 0, n, buf, 1023);
+ if (len < 0) {
+ if (try-- > 0) {
+ sleep(1);
+ continue;
+ }
+ printf("\rCan't upload next block: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+
+ printf("\rFirmware upload ... %d bytes ", n * 1023 + len);
+ fflush(stdout);
+
+ for (i = 0; i < len; i++)
+ crc = crc32_byte(crc, buf[i]);
+
+ if (len > 0) {
+ if (write(fd, buf, len) < 0) {
+ printf("\rCan't write next block: %s (%d)\n", strerror(errno), errno);
+ goto done;
+ }
+ }
+
+ n++;
+ if (len != 1023)
+ break;
+ }
+ printf("\n");
+
+ suffix.bcdDFU = cpu_to_le16(0x0100);
+ suffix.ucDfuSignature[0] = 'U';
+ suffix.ucDfuSignature[1] = 'F';
+ suffix.ucDfuSignature[2] = 'D';
+ suffix.bLength = DFU_SUFFIX_SIZE;
+
+ memcpy(buf, &suffix, DFU_SUFFIX_SIZE);
+ for (i = 0; i < DFU_SUFFIX_SIZE - 4; i++)
+ crc = crc32_byte(crc, buf[i]);
+
+ suffix.dwCRC = cpu_to_le32(crc);
+
+ if (write(fd, &suffix, DFU_SUFFIX_SIZE) < 0)
+ printf("Can't write suffix block: %s (%d)\n", strerror(errno), errno);
+
+done:
+ close(fd);
+
+ usb_release_interface(udev, 0);
+ usb_reset(udev);
+ usb_close(udev);
+}
+
+struct {
+ char *cmd;
+ char *alt;
+ void (*func)(char *device, int argc, char **argv);
+ char *opt;
+ char *doc;
+} command[] = {
+ { "verify", "check", cmd_verify, "<dfu-file>", "Check firmware file" },
+ { "modify", "change", cmd_modify, "<dfu-file>", "Change firmware attributes" },
+ { "upgrade", "download", cmd_upgrade, "<dfu-file>", "Download a new firmware" },
+ { "archive", "upload", cmd_archive, "<dfu-file>", "Upload the current firmware" },
+ { NULL, NULL, NULL, 0, 0 }
+};
+
+static void usage(void)
+{
+ int i;
+
+ printf("dfutool - Device Firmware Upgrade utility ver %s\n\n", VERSION);
+
+ printf("Usage:\n"
+ "\tdfutool [options] <command>\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-d, --device <device> USB device\n"
+ "\t-h, --help Display help\n"
+ "\n");
+
+ printf("Commands:\n");
+ for (i = 0; command[i].cmd; i++)
+ printf("\t%-8s %-10s\t%s\n", command[i].cmd,
+ command[i].opt ? command[i].opt : " ",
+ command[i].doc);
+ printf("\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device", 1, 0, 'd' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ char *device = NULL;
+ int i, opt;
+
+ while ((opt = getopt_long(argc, argv, "+d:h", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'd':
+ device = strdup(optarg);
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+
+ default:
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ usb_init();
+
+ for (i = 0; command[i].cmd; i++) {
+ if (strcmp(command[i].cmd, argv[0]) && strcmp(command[i].alt, argv[0]))
+ continue;
+ command[i].func(device, argc, argv);
+ exit(0);
+ }
+
+ usage();
+ exit(1);
+}
diff --git a/utils/tools/example.psr b/utils/tools/example.psr
new file mode 100644
index 00000000..bbbec73a
--- /dev/null
+++ b/utils/tools/example.psr
@@ -0,0 +1,12 @@
+// PSKEY_BDADDR
+&0001 = 0001 2821 005b 6789
+// PSKEY_ANA_FTRIM
+&01f6 = 0025
+// PSKEY_HOST_INTERFACE
+&01f9 = 0001
+// PSKEY_UART_BAUD_RATE
+&0204 = 01d8
+// PSKEY_ANA_FREQ
+&01fe = 0004
+// PSKEY_UART_CONFIG
+&0205 = 0006
diff --git a/utils/tools/hciattach.8 b/utils/tools/hciattach.8
new file mode 100644
index 00000000..f9d295eb
--- /dev/null
+++ b/utils/tools/hciattach.8
@@ -0,0 +1,122 @@
+.TH HCIATTACH 8 "Jan 22 2002" BlueZ "Linux System Administration"
+.SH NAME
+hciattach \- attach serial devices via UART HCI to BlueZ stack
+.SH SYNOPSIS
+.B hciattach
+.RB [\| \-n \|]
+.RB [\| \-p \|]
+.RB [\| \-t
+.IR timeout \|]
+.I tty
+.IR type \||\| id
+.I speed
+.I flow
+.I bdaddr
+.SH DESCRIPTION
+.LP
+Hciattach is used to attach a serial UART to the Bluetooth stack as HCI
+transport interface.
+.SH OPTIONS
+.TP
+.B \-n
+Don't detach from controlling terminal.
+.TP
+.B \-p
+Print the PID when detaching.
+.TP
+.BI \-t " timeout"
+Specify an initialization timeout. (Default is 5 seconds.)
+.TP
+.I tty
+This specifies the serial device to attach. A leading
+.B /dev
+can be omitted. Examples:
+.B /dev/ttyS1
+.B ttyS2
+.TP
+.IR type \||\| id
+The
+.I type
+or
+.I id
+of the Bluetooth device that is to be attached, i.e. vendor or other device
+specific identifier. Currently supported types are
+.RS
+.TP
+.B type
+.B description
+.TP
+.B any
+Unspecified HCI_UART interface, no vendor specific options
+.TP
+.B ericsson
+Ericsson based modules
+.TP
+.B digi
+Digianswer based cards
+.TP
+.B xircom
+Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter
+.TP
+.B csr
+CSR Casira serial adapter or BrainBoxes serial dongle (BL642)
+.TP
+.B bboxes
+BrainBoxes PCMCIA card (BL620)
+.TP
+.B swave
+Silicon Wave kits
+.TP
+.B bcsp
+Serial adapters using CSR chips with BCSP serial protocol
+.RE
+
+Supported IDs are (manufacturer id, product id)
+.RS
+.TP
+.B 0x0105, 0x080a
+Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter
+.TP
+.B 0x0160, 0x0002
+BrainBoxes PCMCIA card (BL620)
+.RE
+
+.TP
+.I speed
+The
+.I speed
+specifies the UART speed to use. Baudrates higher than 115.200bps require
+vendor specific initializations that are not implemented for all types of
+devices. In general the following speeds are supported:
+
+.B 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+
+Supported vendor devices are automatically initialised to their respective
+best settings.
+.TP
+.I flow
+If the keyword
+.I flow
+is appended to the list of options then hardware flow control is forced on
+the serial link (
+.B CRTSCTS
+). All above mentioned device types have
+.B flow
+set by default. To force no flow control use
+.B noflow
+instead.
+
+.TP
+.I bdaddr
+The
+.I bdaddr
+specifies the Bluetooth Address to use. Some devices (like the STLC2500)
+do not store the Bluetooth address in hardware memory. Instead it must
+be uploaded during the initialization process. If this argument
+is specified, then the address will be used to initialize the device.
+Otherwise, a default address will be used.
+
+.SH AUTHORS
+Written by Maxim Krasnyansky <maxk@qualcomm.com>
+.PP
+Manual page by Nils Faerber <nils@kernelconcepts.de>
diff --git a/utils/tools/hciattach.c b/utils/tools/hciattach.c
new file mode 100644
index 00000000..36f3c72b
--- /dev/null
+++ b/utils/tools/hciattach.c
@@ -0,0 +1,1392 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#ifndef N_HCI
+#define N_HCI 15
+#endif
+
+#define HCIUARTSETPROTO _IOW('U', 200, int)
+#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTGETDEVICE _IOR('U', 202, int)
+
+#define HCI_UART_H4 0
+#define HCI_UART_BCSP 1
+#define HCI_UART_3WIRE 2
+#define HCI_UART_H4DS 3
+
+struct uart_t {
+ char *type;
+ int m_id;
+ int p_id;
+ int proto;
+ int init_speed;
+ int speed;
+ int flags;
+ char *bdaddr;
+ int (*init) (int fd, struct uart_t *u, struct termios *ti);
+};
+
+#define FLOW_CTL 0x0001
+
+static volatile sig_atomic_t __io_canceled = 0;
+
+static void sig_hup(int sig)
+{
+}
+
+static void sig_term(int sig)
+{
+ __io_canceled = 1;
+}
+
+static void sig_alarm(int sig)
+{
+ fprintf(stderr, "Initialization timed out.\n");
+ exit(1);
+}
+
+static int uart_speed(int s)
+{
+ switch (s) {
+ case 9600:
+ return B9600;
+ case 19200:
+ return B19200;
+ case 38400:
+ return B38400;
+ case 57600:
+ return B57600;
+ case 115200:
+ return B115200;
+ case 230400:
+ return B230400;
+ case 460800:
+ return B460800;
+ case 500000:
+ return B500000;
+ case 576000:
+ return B576000;
+ case 921600:
+ return B921600;
+ case 1000000:
+ return B1000000;
+ case 1152000:
+ return B1152000;
+ case 1500000:
+ return B1500000;
+ case 2000000:
+ return B2000000;
+#ifdef B2500000
+ case 2500000:
+ return B2500000;
+#endif
+#ifdef B3000000
+ case 3000000:
+ return B3000000;
+#endif
+#ifdef B3500000
+ case 3500000:
+ return B3500000;
+#endif
+#ifdef B4000000
+ case 4000000:
+ return B4000000;
+#endif
+ default:
+ return B57600;
+ }
+}
+
+static int set_speed(int fd, struct termios *ti, int speed)
+{
+ cfsetospeed(ti, uart_speed(speed));
+ return tcsetattr(fd, TCSANOW, ti);
+}
+
+/*
+ * Read an HCI event from the given file descriptor.
+ */
+static int read_hci_event(int fd, unsigned char* buf, int size)
+{
+ int remain, r;
+ int count = 0;
+
+ if (size <= 0)
+ return -1;
+
+ /* The first byte identifies the packet type. For HCI event packets, it
+ * should be 0x04, so we read until we get to the 0x04. */
+ while (1) {
+ r = read(fd, buf, 1);
+ if (r <= 0)
+ return -1;
+ if (buf[0] == 0x04)
+ break;
+ }
+ count++;
+
+ /* The next two bytes are the event code and parameter total length. */
+ while (count < 3) {
+ r = read(fd, buf + count, 3 - count);
+ if (r <= 0)
+ return -1;
+ count += r;
+ }
+
+ /* Now we read the parameters. */
+ if (buf[2] < (size - 3))
+ remain = buf[2];
+ else
+ remain = size - 3;
+
+ while ((count - 3) < remain) {
+ r = read(fd, buf + count, remain - (count - 3));
+ if (r <= 0)
+ return -1;
+ count += r;
+ }
+
+ return count;
+}
+
+/*
+ * Ericsson specific initialization
+ */
+static int ericsson(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = {0, 50000};
+ char cmd[5];
+
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x09;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x01;
+
+ switch (u->speed) {
+ case 57600:
+ cmd[4] = 0x03;
+ break;
+ case 115200:
+ cmd[4] = 0x02;
+ break;
+ case 230400:
+ cmd[4] = 0x01;
+ break;
+ case 460800:
+ cmd[4] = 0x00;
+ break;
+ case 921600:
+ cmd[4] = 0x20;
+ break;
+ case 2000000:
+ cmd[4] = 0x25;
+ break;
+ case 3000000:
+ cmd[4] = 0x27;
+ break;
+ case 4000000:
+ cmd[4] = 0x2B;
+ break;
+ default:
+ cmd[4] = 0x03;
+ u->speed = 57600;
+ fprintf(stderr, "Invalid speed requested, using %d bps instead\n", u->speed);
+ break;
+ }
+
+ /* Send initialization command */
+ if (write(fd, cmd, 5) != 5) {
+ perror("Failed to write init command");
+ return -1;
+ }
+
+ nanosleep(&tm, NULL);
+ return 0;
+}
+
+/*
+ * Digianswer specific initialization
+ */
+static int digi(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = {0, 50000};
+ char cmd[5];
+
+ /* DigiAnswer set baud rate command */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x07;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x01;
+
+ switch (u->speed) {
+ case 57600:
+ cmd[4] = 0x08;
+ break;
+ case 115200:
+ cmd[4] = 0x09;
+ break;
+ default:
+ cmd[4] = 0x09;
+ u->speed = 115200;
+ break;
+ }
+
+ /* Send initialization command */
+ if (write(fd, cmd, 5) != 5) {
+ perror("Failed to write init command");
+ return -1;
+ }
+
+ nanosleep(&tm, NULL);
+ return 0;
+}
+
+static int texas(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = {0, 50000};
+ char cmd[4];
+ unsigned char resp[100]; /* Response */
+ int n;
+
+ memset(resp,'\0', 100);
+
+ /* 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 */
+
+ /* Get Manufacturer and LMP version */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x01;
+ cmd[2] = 0x10;
+ cmd[3] = 0x00;
+
+ do {
+ n = write(fd, cmd, 4);
+ if (n < 0) {
+ perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)");
+ return -1;
+ }
+ if (n < 4) {
+ fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);
+ return -1;
+ }
+
+ /* Read reply. */
+ if (read_hci_event(fd, resp, 100) < 0) {
+ perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)");
+ return -1;
+ }
+
+ /* Wait for command complete event for our Opcode */
+ } while (resp[4] != cmd[1] && resp[5] != cmd[2]);
+
+ /* Verify manufacturer */
+ if ((resp[11] & 0xFF) != 0x0d)
+ fprintf(stderr,"WARNING : module's manufacturer is not Texas Instrument\n");
+
+ /* Print LMP version */
+ fprintf(stderr, "Texas module LMP version : 0x%02x\n", resp[10] & 0xFF);
+
+ /* Print LMP subversion */
+ fprintf(stderr, "Texas module LMP sub-version : 0x%02x%02x\n", resp[14] & 0xFF, resp[13] & 0xFF);
+
+ nanosleep(&tm, NULL);
+ return 0;
+}
+
+static int read_check(int fd, void *buf, int count)
+{
+ int res;
+
+ do {
+ res = read(fd, buf, count);
+ if (res != -1) {
+ buf += res;
+ count -= res;
+ }
+ } while (count && (errno == 0 || errno == EINTR));
+
+ if (count)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * BCSP specific initialization
+ */
+int serial_fd;
+
+static void bcsp_tshy_sig_alarm(int sig)
+{
+ static int retries=0;
+ unsigned char bcsp_sync_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0};
+ int len;
+
+ if (retries < 10) {
+ retries++;
+ len = write(serial_fd, &bcsp_sync_pkt, 10);
+ alarm(1);
+ return;
+ }
+
+ tcflush(serial_fd, TCIOFLUSH);
+ fprintf(stderr, "BCSP initialization timed out\n");
+ exit(1);
+}
+
+static void bcsp_tconf_sig_alarm(int sig)
+{
+ static int retries=0;
+ unsigned char bcsp_conf_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0};
+ int len;
+
+ if (retries < 10){
+ retries++;
+ len = write(serial_fd, &bcsp_conf_pkt, 10);
+ alarm(1);
+ return;
+ }
+
+ tcflush(serial_fd, TCIOFLUSH);
+ fprintf(stderr, "BCSP initialization timed out\n");
+ exit(1);
+}
+
+static int bcsp(int fd, struct uart_t *u, struct termios *ti)
+{
+ unsigned char byte, bcsph[4], bcspp[4],
+ bcsp_sync_resp_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xac,0xaf,0xef,0xee,0xc0},
+ bcsp_conf_resp_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xde,0xad,0xd0,0xd0,0xc0},
+ bcspsync[4] = {0xda, 0xdc, 0xed, 0xed},
+ bcspsyncresp[4] = {0xac,0xaf,0xef,0xee},
+ bcspconf[4] = {0xad,0xef,0xac,0xed},
+ bcspconfresp[4] = {0xde,0xad,0xd0,0xd0};
+ struct sigaction sa;
+ int len;
+
+ if (set_speed(fd, ti, u->speed) < 0) {
+ perror("Can't set default baud rate");
+ return -1;
+ }
+
+ ti->c_cflag |= PARENB;
+ ti->c_cflag &= ~(PARODD);
+
+ if (tcsetattr(fd, TCSANOW, ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+
+ alarm(0);
+
+ serial_fd = fd;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = bcsp_tshy_sig_alarm;
+ sigaction(SIGALRM, &sa, NULL);
+
+ /* State = shy */
+
+ bcsp_tshy_sig_alarm(0);
+ while (1) {
+ do {
+ if (read_check(fd, &byte, 1) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+ } while (byte != 0xC0);
+
+ do {
+ if ( read_check(fd, &bcsph[0], 1) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+ } while (bcsph[0] == 0xC0);
+
+ if ( read_check(fd, &bcsph[1], 3) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+
+ if (((bcsph[0] + bcsph[1] + bcsph[2]) & 0xFF) != (unsigned char)~bcsph[3])
+ continue;
+ if (bcsph[1] != 0x41 || bcsph[2] != 0x00)
+ continue;
+
+ if (read_check(fd, &bcspp, 4) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+
+ if (!memcmp(bcspp, bcspsync, 4)) {
+ len = write(fd, &bcsp_sync_resp_pkt,10);
+ } else if (!memcmp(bcspp, bcspsyncresp, 4))
+ break;
+ }
+
+ /* State = curious */
+
+ alarm(0);
+ sa.sa_handler = bcsp_tconf_sig_alarm;
+ sigaction(SIGALRM, &sa, NULL);
+ alarm(1);
+
+ while (1) {
+ do {
+ if (read_check(fd, &byte, 1) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+ } while (byte != 0xC0);
+
+ do {
+ if (read_check(fd, &bcsph[0], 1) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+ } while (bcsph[0] == 0xC0);
+
+ if (read_check(fd, &bcsph[1], 3) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+
+ if (((bcsph[0] + bcsph[1] + bcsph[2]) & 0xFF) != (unsigned char)~bcsph[3])
+ continue;
+
+ if (bcsph[1] != 0x41 || bcsph[2] != 0x00)
+ continue;
+
+ if (read_check(fd, &bcspp, 4) == -1){
+ perror("Failed to read");
+ return -1;
+ }
+
+ if (!memcmp(bcspp, bcspsync, 4))
+ len = write(fd, &bcsp_sync_resp_pkt, 10);
+ else if (!memcmp(bcspp, bcspconf, 4))
+ len = write(fd, &bcsp_conf_resp_pkt, 10);
+ else if (!memcmp(bcspp, bcspconfresp, 4))
+ break;
+ }
+
+ /* State = garrulous */
+
+ return 0;
+}
+
+/*
+ * CSR specific initialization
+ * Inspired strongly by code in OpenBT and experimentations with Brainboxes
+ * Pcmcia card.
+ * Jean Tourrilhes <jt@hpl.hp.com> - 14.11.01
+ */
+static int csr(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = {0, 10000000}; /* 10ms - be generous */
+ unsigned char cmd[30]; /* Command */
+ unsigned char resp[30]; /* Response */
+ int clen = 0; /* Command len */
+ static int csr_seq = 0; /* Sequence number of command */
+ int divisor;
+
+ /* It seems that if we set the CSR UART speed straight away, it
+ * won't work, the CSR UART gets into a state where we can't talk
+ * to it anymore.
+ * On the other hand, doing a read before setting the CSR speed
+ * seems to be ok.
+ * Therefore, the strategy is to read the build ID (useful for
+ * debugging) and only then set the CSR UART speed. Doing like
+ * this is more complex but at least it works ;-)
+ * The CSR UART control may be slow to wake up or something because
+ * every time I read its speed, its bogus...
+ * Jean II */
+
+ /* Try to read the build ID of the CSR chip */
+ clen = 5 + (5 + 6) * 2;
+ /* HCI header */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x00; /* CSR command */
+ cmd[2] = 0xfc; /* MANUFACTURER_SPEC */
+ cmd[3] = 1 + (5 + 6) * 2; /* len */
+ /* CSR MSG header */
+ cmd[4] = 0xC2; /* first+last+channel=BCC */
+ /* CSR BCC header */
+ cmd[5] = 0x00; /* type = GET-REQ */
+ cmd[6] = 0x00; /* - msB */
+ cmd[7] = 5 + 4; /* len */
+ cmd[8] = 0x00; /* - msB */
+ cmd[9] = csr_seq & 0xFF;/* seq num */
+ cmd[10] = (csr_seq >> 8) & 0xFF; /* - msB */
+ csr_seq++;
+ cmd[11] = 0x19; /* var_id = CSR_CMD_BUILD_ID */
+ cmd[12] = 0x28; /* - msB */
+ cmd[13] = 0x00; /* status = STATUS_OK */
+ cmd[14] = 0x00; /* - msB */
+ /* CSR BCC payload */
+ memset(cmd + 15, 0, 6 * 2);
+
+ /* Send command */
+ do {
+ if (write(fd, cmd, clen) != clen) {
+ perror("Failed to write init command (GET_BUILD_ID)");
+ return -1;
+ }
+
+ /* Read reply. */
+ if (read_hci_event(fd, resp, 100) < 0) {
+ perror("Failed to read init response (GET_BUILD_ID)");
+ return -1;
+ }
+
+ /* Event code 0xFF is for vendor-specific events, which is
+ * what we're looking for. */
+ } while (resp[1] != 0xFF);
+
+#ifdef CSR_DEBUG
+ {
+ char temp[512];
+ int i;
+ for (i=0; i < rlen; i++)
+ sprintf(temp + (i*3), "-%02X", resp[i]);
+ fprintf(stderr, "Reading CSR build ID %d [%s]\n", rlen, temp + 1);
+ // In theory, it should look like :
+ // 04-FF-13-FF-01-00-09-00-00-00-19-28-00-00-73-00-00-00-00-00-00-00
+ }
+#endif
+ /* Display that to user */
+ 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 */
+ clen = 5 + (5 + 4)*2;
+ /* -- HCI header */
+ cmd[3] = 1 + (5 + 4)*2; /* len */
+ /* -- CSR BCC header -- */
+ cmd[9] = csr_seq & 0xFF; /* seq num */
+ cmd[10] = (csr_seq >> 8) & 0xFF; /* - msB */
+ csr_seq++;
+ cmd[11] = 0x02; /* var_id = CONFIG_UART */
+ cmd[12] = 0x68; /* - msB */
+
+#ifdef CSR_DEBUG
+ /* Send command */
+ do {
+ if (write(fd, cmd, clen) != clen) {
+ perror("Failed to write init command (GET_BUILD_ID)");
+ return -1;
+ }
+
+ /* Read reply. */
+ if (read_hci_event(fd, resp, 100) < 0) {
+ perror("Failed to read init response (GET_BUILD_ID)");
+ return -1;
+ }
+
+ /* Event code 0xFF is for vendor-specific events, which is
+ * what we're looking for. */
+ } while (resp[1] != 0xFF);
+
+ {
+ char temp[512];
+ int i;
+ for (i=0; i < rlen; i++)
+ sprintf(temp + (i*3), "-%02X", resp[i]);
+ fprintf(stderr, "Reading CSR UART speed %d [%s]\n", rlen, temp+1);
+ }
+#endif
+
+ if (u->speed > 1500000) {
+ 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) {
+ /* Unknown speed. Why oh why can't we just pass an int to the kernel? */
+ fprintf(stderr, "Speed %d unrecognised. Remaining at %d baud\n",
+ u->speed, u->init_speed);
+ u->speed = u->init_speed;
+ }
+ if (u->speed == u->init_speed)
+ return 0;
+
+ /* Now, create the command that will set the UART speed */
+ /* CSR BCC header */
+ cmd[5] = 0x02; /* type = SET-REQ */
+ cmd[6] = 0x00; /* - msB */
+ cmd[9] = csr_seq & 0xFF; /* seq num */
+ cmd[10] = (csr_seq >> 8) & 0xFF;/* - msB */
+ csr_seq++;
+
+ divisor = (u->speed*64+7812)/15625;
+
+ /* No parity, one stop bit -> divisor |= 0x0000; */
+ cmd[15] = (divisor) & 0xFF; /* divider */
+ cmd[16] = (divisor >> 8) & 0xFF; /* - msB */
+ /* The rest of the payload will be 0x00 */
+
+#ifdef CSR_DEBUG
+ {
+ char temp[512];
+ int i;
+ for(i = 0; i < clen; i++)
+ sprintf(temp + (i*3), "-%02X", cmd[i]);
+ fprintf(stderr, "Writing CSR UART speed %d [%s]\n", clen, temp + 1);
+ // In theory, it should look like :
+ // 01-00-FC-13-C2-02-00-09-00-03-00-02-68-00-00-BF-0E-00-00-00-00-00-00
+ // 01-00-FC-13-C2-02-00-09-00-01-00-02-68-00-00-D8-01-00-00-00-00-00-00
+ }
+#endif
+
+ /* Send the command to set the CSR UART speed */
+ if (write(fd, cmd, clen) != clen) {
+ perror("Failed to write init command (SET_UART_SPEED)");
+ return -1;
+ }
+
+ nanosleep(&tm, NULL);
+ return 0;
+}
+
+/*
+ * Silicon Wave specific initialization
+ * Thomas Moser <thomas.moser@tmoser.ch>
+ */
+static int swave(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = { 0, 500000 };
+ char cmd[10], rsp[100];
+ int r;
+
+ // Silicon Wave set baud rate command
+ // see HCI Vendor Specific Interface from Silicon Wave
+ // first send a "param access set" command to set the
+ // appropriate data fields in RAM. Then send a "HCI Reset
+ // 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[2] = 0xfc; // OGF bx111111 = vendor specific
+ cmd[3] = 0x06; // 6 bytes of data following
+ cmd[4] = 0x01; // param sub command
+ cmd[5] = 0x11; // tag 17 = 0x11 = HCI Transport Params
+ cmd[6] = 0x03; // length of the parameter following
+ cmd[7] = 0x01; // HCI Transport flow control enable
+ cmd[8] = 0x01; // HCI Transport Type = UART
+
+ switch (u->speed) {
+ case 19200:
+ cmd[9] = 0x03;
+ break;
+ case 38400:
+ cmd[9] = 0x02;
+ break;
+ case 57600:
+ cmd[9] = 0x01;
+ break;
+ case 115200:
+ cmd[9] = 0x00;
+ break;
+ default:
+ u->speed = 115200;
+ cmd[9] = 0x00;
+ break;
+ }
+
+ /* Send initialization command */
+ if (write(fd, cmd, 10) != 10) {
+ perror("Failed to write init command");
+ 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
+ // until correct answer, else error handling ... todo ...
+
+ nanosleep(&tm, NULL);
+
+ r = read(fd, rsp, sizeof(rsp));
+ if (r > 0) {
+ // guess it's okay, but we should parse the reply. But since
+ // I don't react on an error anyway ... todo
+ // Response packet format:
+ // 04 Event
+ // FF Vendor specific
+ // 07 Parameter length
+ // 0B Subcommand
+ // 01 Setevent
+ // 11 Tag specifying HCI Transport Layer Parameter
+ // 03 length
+ // 01 flow on
+ // 01 Hci Transport type = Uart
+ // xx Baud rate set (see above)
+ } else {
+ // ups, got error.
+ return -1;
+ }
+
+ // we probably got the reply. Now we must send the "soft reset"
+ // which is standard HCI RESET.
+
+ cmd[0] = HCI_COMMAND_PKT; // it's a command packet
+ cmd[1] = 0x03;
+ cmd[2] = 0x0c;
+ cmd[3] = 0x00;
+
+ /* Send reset command */
+ if (write(fd, cmd, 4) != 4) {
+ perror("Can't write Silicon Wave reset cmd.");
+ return -1;
+ }
+
+ nanosleep(&tm, NULL);
+
+ // now the uart baud rate on the silicon wave module is set and effective.
+ // change our own baud rate as well. Then there is a reset event comming in
+ // on the *new* baud rate. This is *undocumented*! The packet looks like this:
+ // 04 FF 01 0B (which would make that a confirmation of 0x0B = "Param
+ // subcommand class". So: change to new baud rate, read with timeout, parse
+ // data, error handling. BTW: all param access in Silicon Wave is done this way.
+ // Maybe this code would belong in a seperate file, or at least code reuse...
+
+ return 0;
+}
+
+/*
+ * ST Microelectronics specific initialization
+ * Marcel Holtmann <marcel@holtmann.org>
+ */
+static int st(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = {0, 50000};
+ char cmd[5];
+
+ /* ST Microelectronics set baud rate command */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x46; // OCF = Hci_Cmd_ST_Set_Uart_Baud_Rate
+ cmd[2] = 0xfc; // OGF = Vendor specific
+ cmd[3] = 0x01;
+
+ switch (u->speed) {
+ case 9600:
+ cmd[4] = 0x09;
+ break;
+ case 19200:
+ cmd[4] = 0x0b;
+ break;
+ case 38400:
+ cmd[4] = 0x0d;
+ break;
+ case 57600:
+ cmd[4] = 0x0e;
+ break;
+ case 115200:
+ cmd[4] = 0x10;
+ break;
+ case 230400:
+ cmd[4] = 0x12;
+ break;
+ case 460800:
+ cmd[4] = 0x13;
+ break;
+ case 921600:
+ cmd[4] = 0x14;
+ break;
+ default:
+ cmd[4] = 0x10;
+ u->speed = 115200;
+ break;
+ }
+
+ /* Send initialization command */
+ if (write(fd, cmd, 5) != 5) {
+ perror("Failed to write init command");
+ return -1;
+ }
+
+ nanosleep(&tm, NULL);
+ return 0;
+}
+
+extern int stlc2500_init(int fd, bdaddr_t *bdaddr);
+
+static int stlc2500(int fd, struct uart_t *u, struct termios *ti)
+{
+ bdaddr_t bdaddr;
+ unsigned char resp[10];
+ int n;
+ int rvalue;
+
+ /* STLC2500 has an ericsson core */
+ rvalue = ericsson(fd, u, ti);
+ if (rvalue != 0)
+ return rvalue;
+
+#ifdef STLC2500_DEBUG
+ fprintf(stderr, "Setting speed\n");
+#endif
+ if (set_speed(fd, ti, u->speed) < 0) {
+ perror("Can't set baud rate");
+ return -1;
+ }
+
+#ifdef STLC2500_DEBUG
+ fprintf(stderr, "Speed set...\n");
+#endif
+
+ /* Read reply */
+ if ((n = read_hci_event(fd, resp, 10)) < 0) {
+ fprintf(stderr, "Failed to set baud rate on chip\n");
+ return -1;
+ }
+
+#ifdef STLC2500_DEBUG
+ for (i = 0; i < n; i++) {
+ fprintf(stderr, "resp[%d] = %02x\n", i, resp[i]);
+ }
+#endif
+
+ str2ba(u->bdaddr, &bdaddr);
+ return stlc2500_init(fd, &bdaddr);
+}
+
+extern int bgb2xx_init(int fd, bdaddr_t *bdaddr);
+
+static int bgb2xx(int fd, struct uart_t *u, struct termios *ti)
+{
+ bdaddr_t bdaddr;
+
+ str2ba(u->bdaddr, &bdaddr);
+
+ return bgb2xx_init(fd, &bdaddr);
+}
+
+/*
+ * Broadcom specific initialization
+ * Extracted from Jungo openrg
+ */
+static int bcm2035(int fd, struct uart_t *u, struct termios *ti)
+{
+ int n;
+ unsigned char cmd[30], resp[30];
+
+ /* Reset the BT Chip */
+ memset(cmd, 0, sizeof(cmd));
+ memset(resp, 0, sizeof(resp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x03;
+ cmd[2] = 0x0c;
+ cmd[3] = 0x00;
+
+ /* Send command */
+ if (write(fd, cmd, 4) != 4) {
+ fprintf(stderr, "Failed to write reset command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if ((n = read_hci_event(fd, resp, 4)) < 0) {
+ fprintf(stderr, "Failed to reset chip\n");
+ return -1;
+ }
+
+ if (u->bdaddr != NULL) {
+ /* Set BD_ADDR */
+ memset(cmd, 0, sizeof(cmd));
+ memset(resp, 0, sizeof(resp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x01;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *) (cmd + 4));
+
+ /* Send command */
+ if (write(fd, cmd, 10) != 10) {
+ fprintf(stderr, "Failed to write BD_ADDR command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if ((n = read_hci_event(fd, resp, 10)) < 0) {
+ fprintf(stderr, "Failed to set BD_ADDR\n");
+ return -1;
+ }
+ }
+
+ /* Read the local version info */
+ memset(cmd, 0, sizeof(cmd));
+ memset(resp, 0, sizeof(resp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x01;
+ cmd[2] = 0x10;
+ cmd[3] = 0x00;
+
+ /* Send command */
+ if (write(fd, cmd, 4) != 4) {
+ fprintf(stderr, "Failed to write \"read local version\" "
+ "command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if ((n = read_hci_event(fd, resp, 4)) < 0) {
+ fprintf(stderr, "Failed to read local version\n");
+ return -1;
+ }
+
+ /* Read the local supported commands info */
+ memset(cmd, 0, sizeof(cmd));
+ memset(resp, 0, sizeof(resp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x02;
+ cmd[2] = 0x10;
+ cmd[3] = 0x00;
+
+ /* Send command */
+ if (write(fd, cmd, 4) != 4) {
+ fprintf(stderr, "Failed to write \"read local supported "
+ "commands\" command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if ((n = read_hci_event(fd, resp, 4)) < 0) {
+ fprintf(stderr, "Failed to read local supported commands\n");
+ return -1;
+ }
+
+ /* Set the baud rate */
+ memset(cmd, 0, sizeof(cmd));
+ memset(resp, 0, sizeof(resp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x18;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x02;
+ switch (u->speed) {
+ case 57600:
+ cmd[4] = 0x00;
+ cmd[5] = 0xe6;
+ break;
+ case 230400:
+ cmd[4] = 0x22;
+ cmd[5] = 0xfa;
+ break;
+ case 460800:
+ cmd[4] = 0x22;
+ cmd[5] = 0xfd;
+ break;
+ case 921600:
+ cmd[4] = 0x55;
+ cmd[5] = 0xff;
+ break;
+ default:
+ /* Default is 115200 */
+ cmd[4] = 0x00;
+ cmd[5] = 0xf3;
+ break;
+ }
+ fprintf(stderr, "Baud rate parameters: DHBR=0x%2x,DLBR=0x%2x\n",
+ cmd[4], cmd[5]);
+
+ /* Send command */
+ if (write(fd, cmd, 6) != 6) {
+ fprintf(stderr, "Failed to write \"set baud rate\" command\n");
+ return -1;
+ }
+
+ if ((n = read_hci_event(fd, resp, 6)) < 0) {
+ fprintf(stderr, "Failed to set baud rate\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+struct uart_t uart[] = {
+ { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, ericsson },
+ { "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200, FLOW_CTL, NULL, digi },
+ { "texas", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, texas },
+
+ { "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+
+ /* Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter */
+ { "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+
+ /* CSR Casira serial adapter or BrainBoxes serial dongle (BL642) */
+ { "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
+
+ /* BrainBoxes PCMCIA card (BL620) */
+ { "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, csr },
+
+ /* Silicon Wave kits */
+ { "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, swave },
+
+ /* ST Microelectronics minikits based on STLC2410/STLC2415 */
+ { "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, st },
+
+ /* ST Microelectronics minikits based on STLC2500 */
+ { "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "00:80:E1:00:AB:BA", stlc2500 },
+
+ /* Philips generic Ericsson IP core based */
+ { "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+
+ /* Philips BGB2xx Module */
+ { "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "BD:B2:10:00:AB:BA", bgb2xx },
+
+ /* Sphinx Electronics PICO Card */
+ { "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+
+ /* Inventel BlueBird Module */
+ { "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+
+ /* COM One Platinium Bluetooth PC Card */
+ { "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+
+ /* TDK Bluetooth PC Card and IBM Bluetooth PC Card II */
+ { "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+
+ /* Socket Bluetooth CF Card (Rev G) */
+ { "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400, 0, NULL, bcsp },
+
+ /* 3Com Bluetooth Card (Version 3.0) */
+ { "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
+
+ /* AmbiCom BT2000C Bluetooth PC/CF Card */
+ { "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800, FLOW_CTL, NULL, csr },
+
+ /* Zoom Bluetooth PCMCIA Card */
+ { "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+
+ /* Sitecom CN-504 PCMCIA Card */
+ { "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+
+ /* Billionton PCBTC1 PCMCIA Card */
+ { "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+
+ /* Broadcom BCM2035 */
+ { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
+
+ { NULL, 0 }
+};
+
+struct uart_t * get_by_id(int m_id, int p_id)
+{
+ int i;
+ for (i = 0; uart[i].type; i++) {
+ if (uart[i].m_id == m_id && uart[i].p_id == p_id)
+ return &uart[i];
+ }
+ return NULL;
+}
+
+struct uart_t * get_by_type(char *type)
+{
+ int i;
+ for (i = 0; uart[i].type; i++) {
+ if (!strcmp(uart[i].type, type))
+ return &uart[i];
+ }
+ return NULL;
+}
+
+/* Initialize UART driver */
+int init_uart(char *dev, struct uart_t *u, int send_break)
+{
+ struct termios ti;
+ int fd, i;
+
+ fd = open(dev, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ perror("Can't open serial port");
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (tcgetattr(fd, &ti) < 0) {
+ perror("Can't get port settings");
+ return -1;
+ }
+
+ cfmakeraw(&ti);
+
+ ti.c_cflag |= CLOCAL;
+ if (u->flags & FLOW_CTL)
+ ti.c_cflag |= CRTSCTS;
+ else
+ ti.c_cflag &= ~CRTSCTS;
+
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+
+ /* Set initial baudrate */
+ if (set_speed(fd, &ti, u->init_speed) < 0) {
+ perror("Can't set initial baud rate");
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (send_break) {
+ tcsendbreak(fd, 0);
+ usleep(500000);
+ }
+
+ if (u->init && u->init(fd, u, &ti) < 0)
+ return -1;
+
+ tcflush(fd, TCIOFLUSH);
+
+ /* Set actual baudrate */
+ if (set_speed(fd, &ti, u->speed) < 0) {
+ perror("Can't set baud rate");
+ return -1;
+ }
+
+ /* Set TTY to N_HCI line discipline */
+ i = N_HCI;
+ if (ioctl(fd, TIOCSETD, &i) < 0) {
+ perror("Can't set line discipline");
+ return -1;
+ }
+
+ if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
+ perror("Can't set device");
+ return -1;
+ }
+
+ return fd;
+}
+
+static void usage(void)
+{
+ 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 -l\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct uart_t *u = NULL;
+ int detach, printpid, opt, i, n, ld, err;
+ int to = 5;
+ int init_speed = 0;
+ int send_break = 0;
+ pid_t pid;
+ struct sigaction sa;
+ struct pollfd p;
+ char dev[PATH_MAX];
+
+ detach = 1;
+ printpid = 0;
+
+ while ((opt=getopt(argc, argv, "bnpt:s:l")) != EOF) {
+ switch(opt) {
+ case 'b':
+ send_break = 1;
+ break;
+
+ case 'n':
+ detach = 0;
+ break;
+
+ case 'p':
+ printpid = 1;
+ break;
+
+ case 't':
+ to = atoi(optarg);
+ break;
+
+ case 's':
+ init_speed = atoi(optarg);
+ break;
+
+ case 'l':
+ for (i = 0; uart[i].type; i++) {
+ printf("%-10s0x%04x,0x%04x\n", uart[i].type,
+ uart[i].m_id, uart[i].p_id);
+ }
+ exit(0);
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ n = argc - optind;
+ if (n < 2) {
+ usage();
+ exit(1);
+ }
+
+ for (n = 0; optind < argc; n++, optind++) {
+ char *opt;
+
+ opt = argv[optind];
+
+ switch(n) {
+ case 0:
+ dev[0] = 0;
+ if (!strchr(opt, '/'))
+ strcpy(dev, "/dev/");
+ strcat(dev, opt);
+ break;
+
+ case 1:
+ if (strchr(argv[optind], ',')) {
+ int m_id, p_id;
+ sscanf(argv[optind], "%x,%x", &m_id, &p_id);
+ u = get_by_id(m_id, p_id);
+ } else {
+ u = get_by_type(opt);
+ }
+
+ if (!u) {
+ fprintf(stderr, "Unknown device type or id\n");
+ exit(1);
+ }
+
+ break;
+
+ case 2:
+ u->speed = atoi(argv[optind]);
+ break;
+
+ case 3:
+ if (!strcmp("flow", argv[optind]))
+ u->flags |= FLOW_CTL;
+ else
+ u->flags &= ~FLOW_CTL;
+ break;
+
+ case 4:
+ u->bdaddr = argv[optind];
+ break;
+ }
+ }
+
+ if (!u) {
+ fprintf(stderr, "Unknown device type or id\n");
+ exit(1);
+ }
+
+ /* If user specified a initial speed, use that instead of
+ the hardware's default */
+ if (init_speed)
+ u->init_speed = init_speed;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = sig_alarm;
+ sigaction(SIGALRM, &sa, NULL);
+
+ /* 5 seconds should be enough for initialization */
+ alarm(to);
+
+ n = init_uart(dev, u, send_break);
+ if (n < 0) {
+ perror("Can't initialize device");
+ exit(1);
+ }
+
+ alarm(0);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ if (detach) {
+ if ((pid = fork())) {
+ if (printpid)
+ printf("%d\n", pid);
+ return 0;
+ }
+
+ for (i = 0; i < 20; i++)
+ if (i != n)
+ close(i);
+ }
+
+ p.fd = n;
+ p.events = POLLERR | POLLHUP;
+
+ while (!__io_canceled) {
+ p.revents = 0;
+ err = poll(&p, 1, 500);
+ if (err < 0 && errno == EINTR)
+ continue;
+ if (err)
+ break;
+ }
+
+ /* Restore TTY line discipline */
+ ld = N_TTY;
+ if (ioctl(n, TIOCSETD, &ld) < 0) {
+ perror("Can't restore line discipline");
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/utils/tools/hciattach_st.c b/utils/tools/hciattach_st.c
new file mode 100644
index 00000000..2c7d7438
--- /dev/null
+++ b/utils/tools/hciattach_st.c
@@ -0,0 +1,276 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/param.h>
+
+#include <bluetooth/bluetooth.h>
+
+static int debug = 0;
+
+static int do_command(int fd, uint8_t ogf, uint16_t ocf,
+ uint8_t *cparam, int clen, uint8_t *rparam, int rlen)
+{
+ //uint16_t opcode = (uint16_t) ((ocf & 0x03ff) | (ogf << 10));
+ unsigned char cp[260], rp[260];
+ int len, size, offset = 3;
+
+ cp[0] = 0x01;
+ cp[1] = ocf & 0xff;
+ cp[2] = ogf << 2 | ocf >> 8;
+ cp[3] = clen;
+
+ if (clen > 0)
+ memcpy(cp + 4, cparam, clen);
+
+ if (debug) {
+ int i;
+ printf("[<");
+ for (i = 0; i < clen + 4; i++)
+ printf(" %02x", cp[i]);
+ printf("]\n");
+ }
+
+ if (write(fd, cp, clen + 4) < 0)
+ return -1;
+
+ do {
+ if (read(fd, rp, 1) < 1)
+ return -1;
+ } while (rp[0] != 0x04);
+
+ if (read(fd, rp + 1, 2) < 2)
+ return -1;
+
+ do {
+ len = read(fd, rp + offset, sizeof(rp) - offset);
+ offset += len;
+ } while (offset < rp[2] + 3);
+
+ if (debug) {
+ int i;
+ printf("[>");
+ for (i = 0; i < offset; i++)
+ printf(" %02x", rp[i]);
+ printf("]\n");
+ }
+
+ if (rp[0] != 0x04) {
+ errno = EIO;
+ return -1;
+ }
+
+ switch (rp[1]) {
+ case 0x0e: /* command complete */
+ if (rp[6] != 0x00)
+ return -ENXIO;
+ offset = 3 + 4;
+ size = rp[2] - 4;
+ break;
+ case 0x0f: /* command status */
+ /* fall through */
+ default:
+ offset = 3;
+ size = rp[2];
+ break;
+ }
+
+ if (!rparam || rlen < size)
+ return -ENXIO;
+
+ memcpy(rparam, rp + offset, size);
+
+ return size;
+}
+
+static int load_file(int dd, uint16_t version, const char *suffix)
+{
+ DIR *dir;
+ struct dirent *d;
+ char pathname[PATH_MAX], filename[NAME_MAX], prefix[20];
+ unsigned char cmd[256];
+ unsigned char buf[256];
+ uint8_t seqnum = 0;
+ int fd, size, len, found_fw_file;
+
+ memset(filename, 0, sizeof(filename));
+
+ snprintf(prefix, sizeof(prefix), "STLC2500_R%d_%02d_",
+ version >> 8, version & 0xff);
+
+ strcpy(pathname, "/lib/firmware");
+ dir = opendir(pathname);
+ if (!dir) {
+ strcpy(pathname, ".");
+ dir = opendir(pathname);
+ if (!dir)
+ return -errno;
+ }
+
+ found_fw_file = 0;
+ while (1) {
+ d = readdir(dir);
+ if (!d)
+ break;
+
+ if (strncmp(d->d_name + strlen(d->d_name) - strlen(suffix),
+ suffix, strlen(suffix)))
+ continue;
+
+ if (strncmp(d->d_name, prefix, strlen(prefix)))
+ continue;
+
+ snprintf(filename, sizeof(filename), "%s/%s",
+ pathname, d->d_name);
+ found_fw_file = 1;
+ }
+
+ closedir(dir);
+
+ if (!found_fw_file)
+ return -ENOENT;
+
+ printf("Loading file %s\n", filename);
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror("Can't open firmware file");
+ return -errno;
+ }
+
+ while (1) {
+ size = read(fd, cmd + 1, 254);
+ if (size <= 0)
+ break;
+
+ cmd[0] = seqnum;
+
+ len = do_command(dd, 0xff, 0x002e, cmd, size + 1, buf, sizeof(buf));
+ if (len < 1)
+ break;
+
+ if (buf[0] != seqnum) {
+ fprintf(stderr, "Sequence number mismatch\n");
+ break;
+ }
+
+ seqnum++;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+int stlc2500_init(int dd, bdaddr_t *bdaddr)
+{
+ unsigned char cmd[16];
+ unsigned char buf[254];
+ uint16_t version;
+ int len;
+ int err;
+
+ /* 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 */
+ len = do_command(dd, 0x04, 0x0001, NULL, 0, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+
+ version = buf[2] << 8 | buf[1];
+
+ err = load_file(dd, version, ".ptc");
+ if (err < 0) {
+ if (err == -ENOENT)
+ fprintf(stderr, "No ROM patch file loaded.\n");
+ else
+ return -1;
+ }
+
+ err = load_file(dd, buf[2] << 8 | buf[1], ".ssf");
+ if (err < 0) {
+ if (err == -ENOENT)
+ fprintf(stderr, "No static settings file loaded.\n");
+ else
+ return -1;
+ }
+
+ cmd[0] = 0xfe;
+ cmd[1] = 0x06;
+ bacpy((bdaddr_t *) (cmd + 2), bdaddr);
+
+ /* Hci_Cmd_ST_Store_In_NVDS */
+ len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+
+ /* HCI_Reset : applies parameters*/
+ len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+
+ return 0;
+}
+
+int bgb2xx_init(int dd, bdaddr_t *bdaddr)
+{
+ unsigned char cmd[16];
+ unsigned char buf[254];
+ int len;
+
+ len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+
+ printf("%s\n", buf);
+
+ cmd[0] = 0xfe;
+ cmd[1] = 0x06;
+ bacpy((bdaddr_t *) (cmd + 2), bdaddr);
+
+ len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+
+ len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/utils/tools/hciconfig.8 b/utils/tools/hciconfig.8
new file mode 100644
index 00000000..f03b1c16
--- /dev/null
+++ b/utils/tools/hciconfig.8
@@ -0,0 +1,276 @@
+.TH HCICONFIG 8 "Nov 11 2002" BlueZ "Linux System Administration"
+.SH NAME
+hciconfig \- configure Bluetooth devices
+.SH SYNOPSIS
+.B hciconfig
+.B \-h
+.br
+.B hciconfig
+.RB [\| \-a \|]
+.br
+.B hciconfig
+.RB [\| \-a \|]
+.RI [\| command
+.RI [\| "command parameters" \|]\|]
+
+.SH DESCRIPTION
+.LP
+.B hciconfig
+is used to configure Bluetooth devices.
+.I hciX
+is the name of a Bluetooth device installed in the system. If
+.I hciX
+is not given,
+.B hciconfig
+prints name and basic information about all the Bluetooth devices installed in
+the system. If
+.I hciX
+is given but no command is given, it prints basic information on device
+.I hciX
+only. Basic information is
+interface type, BD address, ACL MTU, SCO MTU, flags (up, init, running, raw,
+page scan enabled, inquiry scan enabled, inquiry, authentication enabled,
+encryption enabled).
+.SH OPTIONS
+.TP
+.B \-h, \-\-help
+Gives a list of possible commands.
+.TP
+.B \-a, \-\-all
+Other than the basic info, print features, packet type, link policy, link mode,
+name, class, version.
+.SH COMMANDS
+.TP
+.B up
+Open and initialize HCI device.
+.TP
+.B down
+Close HCI device.
+.TP
+.B reset
+Reset HCI device.
+.TP
+.B rstat
+Reset statistic counters.
+.TP
+.B auth
+Enable authentication (sets device to security mode 3).
+.TP
+.B noauth
+Disable authentication.
+.TP
+.B encrypt
+Enable encryption (sets device to security mode 3).
+.TP
+.B noencrypt
+Disable encryption.
+.TP
+.B secmgr
+Enable security manager (current kernel support is limited).
+.TP
+.B nosecmgr
+Disable security manager.
+.TP
+.B piscan
+Enable page and inquiry scan.
+.TP
+.B noscan
+Disable page and inquiry scan.
+.TP
+.B iscan
+Enable inquiry scan, disable page scan.
+.TP
+.B pscan
+Enable page scan, disable inquiry scan.
+.TP
+\fBptype\fP [\fItype\fP]
+With no
+.I type
+, displays the current packet types. Otherwise, all the packet types specified
+by
+.I type
+are set.
+.I type
+is a comma-separated list of packet types, where the possible packet types are
+.BR DM1 ,
+.BR DM3 ,
+.BR DM5 ,
+.BR DH1 ,
+.BR DH3 ,
+.BR DH5 ,
+.BR HV1 ,
+.BR HV2 ,
+.BR HV3 .
+.TP
+.BI name " [name]"
+With no
+.IR name ,
+prints local name. Otherwise, sets local name to
+.IR name .
+.TP
+.BI class " [class]"
+With no
+.IR class ,
+prints class of device. Otherwise, sets class of device to
+.IR class .
+.I
+class
+is a 24-bit hex number describing the class of device, as specified in section
+1.2 of the Bluetooth Assigned Numers document.
+.TP
+.BI voice " [voice]"
+With no
+.IR voice ,
+prints voice setting. Otherwise, sets voice setting to
+.IR voice .
+.I voice
+is a 16-bit hex number describing the voice setting.
+.TP
+.BI iac " [iac]"
+With no
+.IR iac ,
+prints the current IAC setting. Otherwise, sets the IAC to
+.IR iac .
+.TP
+.BI inqtpl " [level]"
+With no
+.IR level ,
+prints out the current inquiry transmit power level. Otherwise, sets
+inquiry transmit power level to
+.IR level .
+.TP
+.BI inqmode " [mode]"
+With no
+.IR mode ,
+prints out the current inquiry mode. Otherwise, sets inquiry mode to
+.IR mode .
+.TP
+.BI inqdata " [data]"
+With no
+.IR name ,
+prints out the current inquiry data. Otherwise, sets inquiry data to
+.IR data .
+.TP
+.BI inqtype " [type]"
+With no
+.IR type ,
+prints out the current inquiry scan type. Otherwise, sets inquiry scan type to
+.IR type .
+.TP
+\fBinqparams\fP [\fIwin\fP:\fIint\fP]
+With no
+.IR win : int ,
+prints inquiry scan window and interval. Otherwise, sets inquiry scan window
+to
+.I win
+slots and inquiry scan interval to
+.I int
+slots.
+.TP
+\fBpageparms\fP [\fIwin\fP:\fIint\fP]
+With no
+.IR win : int ,
+prints page scan window and interval. Otherwise, sets page scan window to
+.I win
+slots and page scan interval to
+.I int
+slots.
+.TP
+.BI pageto " [to]"
+With no
+.IR to ,
+prints page timeout. Otherwise, sets page timeout
+to .I
+to
+slots.
+.TP
+.BI afhmode " [mode]"
+With no
+.IR mode ,
+prints out the current AFH mode. Otherwise, sets AFH mode to
+.IR mode .
+.TP
+.BI sspmode " [mode]"
+With no
+.IR mode ,
+prints out the current Simple Pairing mode. Otherwise, sets Simple Pairing mode to
+.IR mode .
+.TP
+\fBaclmtu\fP \fImtu\fP:\fIpkt\fP
+Sets ACL MTU to
+to
+.I mtu
+bytes and ACL buffer size to
+.I pkt
+packets.
+.TP
+\fBscomtu\fP \fImtu\fP:\fIpkt\fP
+Sets SCO MTU to
+.I mtu
+bytes and SCO buffer size to
+.I pkt
+packets.
+.TP
+.BI putkey " <bdaddr>"
+This command stores the link key for
+.I bdaddr
+on the device.
+.TP
+.BI delkey " <bdaddr>"
+This command deletes the stored link key for
+.I bdaddr
+from the device.
+.TP
+.BI oobdata
+Display local OOB data.
+.TP
+.BI commands
+Display supported commands.
+.TP
+.BI features
+Display device features.
+.TP
+.BI version
+Display version information.
+.TP
+.BI revision
+Display revision information.
+.TP
+.BI lm " [mode]"
+With no
+.I mode
+, prints link mode.
+.B MASTER
+or
+.B SLAVE
+mean, respectively, to ask to become master or to remain slave when a
+connection request comes in. The additional keyword
+.B ACCEPT
+means that baseband connections will be accepted even if there are no
+listening
+.I AF_BLUETOOTH
+sockets.
+.I mode
+is
+.B NONE
+or a comma-separated list of keywords, where possible keywords are
+.B MASTER
+and
+.B "ACCEPT" .
+.B NONE
+sets link policy to the default behaviour of remaining slave and not accepting
+baseband connections when there are no listening
+.I AF_BLUETOOTH
+sockets. If
+.B MASTER
+is present, the device will ask to become master if a connection request comes
+in. If
+.B ACCEPT
+is present, the device will accept baseband connections even when there are no
+listening
+.I AF_BLUETOOTH
+sockets.
+.SH AUTHORS
+Written by Maxim Krasnyansky <maxk@qualcomm.com> and Marcel Holtmann <marcel@holtmann.org>
+.PP
+man page by Fabrizio Gennari <fabrizio.gennari@philips.com>
diff --git a/utils/tools/hciconfig.c b/utils/tools/hciconfig.c
new file mode 100644
index 00000000..a01937b9
--- /dev/null
+++ b/utils/tools/hciconfig.c
@@ -0,0 +1,1749 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "textfile.h"
+#include "csr.h"
+
+static struct hci_dev_info di;
+static int all;
+
+static void print_dev_hdr(struct hci_dev_info *di);
+static void print_dev_info(int ctl, struct hci_dev_info *di);
+
+static void print_dev_list(int ctl, int flags)
+{
+ struct hci_dev_list_req *dl;
+ struct hci_dev_req *dr;
+ int i;
+
+ if (!(dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t)))) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+ dl->dev_num = HCI_MAX_DEV;
+ dr = dl->dev_req;
+
+ if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
+ perror("Can't get device list");
+ exit(1);
+ }
+
+ for (i = 0; i< dl->dev_num; i++) {
+ di.dev_id = (dr+i)->dev_id;
+ if (ioctl(ctl, HCIGETDEVINFO, (void *) &di) < 0)
+ continue;
+ if (hci_test_bit(HCI_RAW, &di.flags) &&
+ !bacmp(&di.bdaddr, BDADDR_ANY)) {
+ int dd = hci_open_dev(di.dev_id);
+ hci_read_bd_addr(dd, &di.bdaddr, 1000);
+ hci_close_dev(dd);
+ }
+ print_dev_info(ctl, &di);
+ }
+}
+
+static void print_pkt_type(struct hci_dev_info *di)
+{
+ printf("\tPacket type: %s\n", hci_ptypetostr(di->pkt_type));
+}
+
+static void print_link_policy(struct hci_dev_info *di)
+{
+ printf("\tLink policy: %s\n", hci_lptostr(di->link_policy));
+}
+
+static void print_link_mode(struct hci_dev_info *di)
+{
+ printf("\tLink mode: %s\n", hci_lmtostr(di->link_mode));
+}
+
+static void print_dev_features(struct hci_dev_info *di, int format)
+{
+ printf("\tFeatures: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
+ "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ di->features[0], di->features[1], di->features[2],
+ di->features[3], di->features[4], di->features[5],
+ di->features[6], di->features[7]);
+
+ if (format) {
+ char *tmp = lmp_featurestostr(di->features, "\t\t", 63);
+ printf("%s\n", tmp);
+ bt_free(tmp);
+ }
+}
+
+static void cmd_rstat(int ctl, int hdev, char *opt)
+{
+ /* Reset HCI device stat counters */
+ if (ioctl(ctl, HCIDEVRESTAT, hdev) < 0) {
+ fprintf(stderr, "Can't reset stats counters hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_scan(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr;
+
+ dr.dev_id = hdev;
+ dr.dev_opt = SCAN_DISABLED;
+ if (!strcmp(opt, "iscan"))
+ dr.dev_opt = SCAN_INQUIRY;
+ else if (!strcmp(opt, "pscan"))
+ dr.dev_opt = SCAN_PAGE;
+ else if (!strcmp(opt, "piscan"))
+ dr.dev_opt = SCAN_PAGE | SCAN_INQUIRY;
+
+ if (ioctl(ctl, HCISETSCAN, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set scan mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_iac(int ctl, int hdev, char *opt)
+{
+ int s = hci_open_dev(hdev);
+
+ if (s < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ if (opt) {
+ int l = strtoul(opt, 0, 16);
+ uint8_t lap[3];
+ if (!strcasecmp(opt, "giac")) {
+ l = 0x9e8b33;
+ } else if (!strcasecmp(opt, "liac")) {
+ l = 0x9e8b00;
+ } else if (l < 0x9e8b00 || l > 0x9e8b3f) {
+ printf("Invalid access code 0x%x\n", l);
+ exit(1);
+ }
+ lap[0] = (l & 0xff);
+ lap[1] = (l >> 8) & 0xff;
+ lap[2] = (l >> 16) & 0xff;
+ if (hci_write_current_iac_lap(s, 1, lap, 1000) < 0) {
+ printf("Failed to set IAC on hci%d: %s\n", hdev, strerror(errno));
+ exit(1);
+ }
+ } else {
+ uint8_t lap[3 * MAX_IAC_LAP];
+ int i, j;
+ uint8_t n;
+ if (hci_read_current_iac_lap(s, &n, lap, 1000) < 0) {
+ printf("Failed to read IAC from hci%d: %s\n", hdev, strerror(errno));
+ exit(1);
+ }
+ print_dev_hdr(&di);
+ printf("\tIAC: ");
+ for (i = 0; i < n; i++) {
+ printf("0x");
+ for (j = 3; j--; )
+ printf("%02x", lap[j + 3 * i]);
+ if (i < n - 1)
+ printf(", ");
+ }
+ printf("\n");
+ }
+ close(s);
+}
+
+static void cmd_auth(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr;
+
+ dr.dev_id = hdev;
+ if (!strcmp(opt, "auth"))
+ dr.dev_opt = AUTH_ENABLED;
+ else
+ dr.dev_opt = AUTH_DISABLED;
+
+ if (ioctl(ctl, HCISETAUTH, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set auth on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_encrypt(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr;
+
+ dr.dev_id = hdev;
+ if (!strcmp(opt, "encrypt"))
+ dr.dev_opt = ENCRYPT_P2P;
+ else
+ dr.dev_opt = ENCRYPT_DISABLED;
+
+ if (ioctl(ctl, HCISETENCRYPT, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set encrypt on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_up(int ctl, int hdev, char *opt)
+{
+ /* Start HCI device */
+ if (ioctl(ctl, HCIDEVUP, hdev) < 0) {
+ if (errno == EALREADY)
+ return;
+ fprintf(stderr, "Can't init device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_down(int ctl, int hdev, char *opt)
+{
+ /* Stop HCI device */
+ if (ioctl(ctl, HCIDEVDOWN, hdev) < 0) {
+ fprintf(stderr, "Can't down device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_reset(int ctl, int hdev, char *opt)
+{
+ /* Reset HCI device */
+#if 0
+ if (ioctl(ctl, HCIDEVRESET, hdev) < 0 ){
+ fprintf(stderr, "Reset failed for device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+#endif
+ cmd_down(ctl, hdev, "down");
+ cmd_up(ctl, hdev, "up");
+}
+
+static void cmd_ptype(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr;
+
+ dr.dev_id = hdev;
+
+ if (hci_strtoptype(opt, &dr.dev_opt)) {
+ if (ioctl(ctl, HCISETPTYPE, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set pkttype on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ print_dev_hdr(&di);
+ print_pkt_type(&di);
+ }
+}
+
+static void cmd_lp(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr;
+
+ dr.dev_id = hdev;
+
+ if (hci_strtolp(opt, &dr.dev_opt)) {
+ if (ioctl(ctl, HCISETLINKPOL, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set link policy on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ print_dev_hdr(&di);
+ print_link_policy(&di);
+ }
+}
+
+static void cmd_lm(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr;
+
+ dr.dev_id = hdev;
+
+ if (hci_strtolm(opt, &dr.dev_opt)) {
+ if (ioctl(ctl, HCISETLINKMODE, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set default link mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ print_dev_hdr(&di);
+ print_link_mode(&di);
+ }
+}
+
+static void cmd_aclmtu(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr = { dev_id: hdev };
+ uint16_t mtu, mpkt;
+
+ if (!opt)
+ return;
+
+ if (sscanf(opt, "%4hu:%4hu", &mtu, &mpkt) != 2)
+ return;
+
+ dr.dev_opt = htobl(htobs(mpkt) | (htobs(mtu) << 16));
+
+ if (ioctl(ctl, HCISETACLMTU, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set ACL mtu on hci%d: %s(%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_scomtu(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_req dr = { dev_id: hdev };
+ uint16_t mtu, mpkt;
+
+ if (!opt)
+ return;
+
+ if (sscanf(opt, "%4hu:%4hu", &mtu, &mpkt) != 2)
+ return;
+
+ dr.dev_opt = htobl(htobs(mpkt) | (htobs(mtu) << 16));
+
+ if (ioctl(ctl, HCISETSCOMTU, (unsigned long) &dr) < 0) {
+ fprintf(stderr, "Can't set SCO mtu on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+}
+
+static void cmd_features(int ctl, int hdev, char *opt)
+{
+ uint8_t max_page, features[8];
+ char *tmp;
+ int i, dd;
+
+ if (!(di.features[7] & LMP_EXT_FEAT)) {
+ print_dev_hdr(&di);
+ print_dev_features(&di, 1);
+ return;
+ }
+
+ dd = hci_open_dev(hdev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (hci_read_local_ext_features(dd, 0, &max_page, features, 1000) < 0) {
+ fprintf(stderr, "Can't read extended features hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ tmp = lmp_featurestostr(di.features, "\t\t", 63);
+ printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
+ "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ (max_page > 0) ? " page 0" : "",
+ features[0], features[1], features[2], features[3],
+ features[4], features[5], features[6], features[7]);
+ printf("%s\n", tmp);
+ bt_free(tmp);
+
+ for (i = 1; i <= max_page; i++) {
+ if (hci_read_local_ext_features(dd, 1, &max_page, features, 1000) < 0)
+ continue;
+
+ printf("\tFeatures page %d: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
+ "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", i,
+ features[0], features[1], features[2], features[3],
+ features[4], features[5], features[6], features[7]);
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_name(int ctl, int hdev, char *opt)
+{
+ int dd;
+
+ 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 (opt) {
+ if (hci_write_local_name(dd, opt, 2000) < 0) {
+ fprintf(stderr, "Can't change local name on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ char name[249];
+ int i;
+
+ if (hci_read_local_name(dd, sizeof(name), name, 1000) < 0) {
+ fprintf(stderr, "Can't read local name on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ for (i = 0; i < 248 && name[i]; i++) {
+ if ((unsigned char) name[i] < 32 || name[i] == 127)
+ name[i] = '.';
+ }
+
+ name[248] = '\0';
+
+ print_dev_hdr(&di);
+ printf("\tName: '%s'\n", name);
+ }
+
+ hci_close_dev(dd);
+}
+
+/*
+ * see http://www.bluetooth.org/assigned-numbers/baseband.htm --- all
+ * strings are reproduced verbatim
+ */
+static char *get_minor_device_name(int major, int minor)
+{
+ switch (major) {
+ case 0: /* misc */
+ return "";
+ case 1: /* computer */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Desktop workstation";
+ case 2:
+ return "Server";
+ case 3:
+ return "Laptop";
+ case 4:
+ return "Handheld";
+ case 5:
+ return "Palm";
+ case 6:
+ return "Wearable";
+ }
+ break;
+ case 2: /* phone */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Cellular";
+ case 2:
+ return "Cordless";
+ case 3:
+ return "Smart phone";
+ case 4:
+ return "Wired modem or voice gateway";
+ case 5:
+ return "Common ISDN Access";
+ case 6:
+ return "Sim Card Reader";
+ }
+ break;
+ case 3: /* lan access */
+ if (minor == 0)
+ return "Uncategorized";
+ switch(minor / 8) {
+ case 0:
+ return "Fully available";
+ case 1:
+ return "1-17% utilized";
+ case 2:
+ return "17-33% utilized";
+ case 3:
+ return "33-50% utilized";
+ case 4:
+ return "50-67% utilized";
+ case 5:
+ return "67-83% utilized";
+ case 6:
+ return "83-99% utilized";
+ case 7:
+ return "No service available";
+ }
+ break;
+ case 4: /* audio/video */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Device conforms to the Headset profile";
+ case 2:
+ return "Hands-free";
+ /* 3 is reserved */
+ case 4:
+ return "Microphone";
+ case 5:
+ return "Loudspeaker";
+ case 6:
+ return "Headphones";
+ case 7:
+ return "Portable Audio";
+ case 8:
+ return "Car Audio";
+ case 9:
+ return "Set-top box";
+ case 10:
+ return "HiFi Audio Device";
+ case 11:
+ return "VCR";
+ case 12:
+ return "Video Camera";
+ case 13:
+ return "Camcorder";
+ case 14:
+ return "Video Monitor";
+ case 15:
+ return "Video Display and Loudspeaker";
+ case 16:
+ return "Video Conferencing";
+ /* 17 is reserved */
+ case 18:
+ return "Gaming/Toy";
+ }
+ break;
+ case 5: /* peripheral */ {
+ static char cls_str[48];
+
+ cls_str[0] = '\0';
+
+ switch(minor & 48) {
+ case 16:
+ strncpy(cls_str, "Keyboard", sizeof(cls_str));
+ break;
+ case 32:
+ strncpy(cls_str, "Pointing device", sizeof(cls_str));
+ break;
+ case 48:
+ strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str));
+ break;
+ }
+ if((minor & 15) && (strlen(cls_str) > 0))
+ strcat(cls_str, "/");
+
+ switch(minor & 15) {
+ case 0:
+ break;
+ case 1:
+ strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 2:
+ strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 3:
+ strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 4:
+ strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 5:
+ strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 6:
+ strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str));
+ break;
+ default:
+ strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str));
+ break;
+ }
+ if(strlen(cls_str) > 0)
+ return cls_str;
+ }
+ case 6: /* imaging */
+ if (minor & 4)
+ return "Display";
+ if (minor & 8)
+ return "Camera";
+ if (minor & 16)
+ return "Scanner";
+ if (minor & 32)
+ return "Printer";
+ break;
+ case 7: /* wearable */
+ switch(minor) {
+ case 1:
+ return "Wrist Watch";
+ case 2:
+ return "Pager";
+ case 3:
+ return "Jacket";
+ case 4:
+ return "Helmet";
+ case 5:
+ return "Glasses";
+ }
+ break;
+ case 8: /* toy */
+ switch(minor) {
+ case 1:
+ return "Robot";
+ case 2:
+ return "Vehicle";
+ case 3:
+ return "Doll / Action Figure";
+ case 4:
+ return "Controller";
+ case 5:
+ return "Game";
+ }
+ break;
+ case 63: /* uncategorised */
+ return "";
+ }
+ return "Unknown (reserved) minor device class";
+}
+
+static void cmd_class(int ctl, int hdev, char *opt)
+{
+ static char *services[] = { "Positioning",
+ "Networking",
+ "Rendering",
+ "Capturing",
+ "Object Transfer",
+ "Audio",
+ "Telephony",
+ "Information" };
+ static char *major_devices[] = { "Miscellaneous",
+ "Computer",
+ "Phone",
+ "LAN Access",
+ "Audio/Video",
+ "Peripheral",
+ "Imaging",
+ "Uncategorized" };
+ int s = hci_open_dev(hdev);
+
+ if (s < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ if (opt) {
+ uint32_t cod = strtoul(opt, NULL, 16);
+ if (hci_write_class_of_dev(s, cod, 2000) < 0) {
+ fprintf(stderr, "Can't write local class of device on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint8_t cls[3];
+ if (hci_read_class_of_dev(s, cls, 1000) < 0) {
+ fprintf(stderr, "Can't read class of device on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ print_dev_hdr(&di);
+ printf("\tClass: 0x%02x%02x%02x\n", cls[2], cls[1], cls[0]);
+ printf("\tService Classes: ");
+ if (cls[2]) {
+ int first = 1;
+ for (s = 0; s < (sizeof(services) / sizeof(*services)); s++)
+ if (cls[2] & (1 << s)) {
+ if (!first)
+ printf(", ");
+ printf(services[s]);
+ first = 0;
+ }
+ } else
+ printf("Unspecified");
+ printf("\n\tDevice Class: ");
+ if ((cls[1] & 0x1f) >= sizeof(major_devices) / sizeof(*major_devices))
+ printf("Invalid Device Class!\n");
+ else
+ printf("%s, %s\n", major_devices[cls[1] & 0x1f],
+ get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2));
+ }
+}
+
+static void cmd_voice(int ctl, int hdev, char *opt)
+{
+ static char *icf[] = { "Linear", "u-Law", "A-Law", "Reserved" };
+ static char *idf[] = { "1's complement", "2's complement", "Sign-Magnitude", "Reserved" };
+ static char *iss[] = { "8 bit", "16 bit" };
+ static char *acf[] = { "CVSD", "u-Law", "A-Law", "Reserved" };
+ int s = hci_open_dev(hdev);
+
+ if (s < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ if (opt) {
+ uint16_t vs = htobs(strtoul(opt, NULL, 16));
+ if (hci_write_voice_setting(s, vs, 2000) < 0) {
+ fprintf(stderr, "Can't write voice setting on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint16_t vs;
+ uint8_t ic;
+ if (hci_read_voice_setting(s, &vs, 1000) < 0) {
+ fprintf(stderr, "Can't read voice setting on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ vs = htobs(vs);
+ ic = (vs & 0x0300) >> 8;
+ print_dev_hdr(&di);
+ printf("\tVoice setting: 0x%04x%s\n", vs,
+ ((vs & 0x03fc) == 0x0060) ? " (Default Condition)" : "");
+ printf("\tInput Coding: %s\n", icf[ic]);
+ printf("\tInput Data Format: %s\n", idf[(vs & 0xc0) >> 6]);
+ if (!ic) {
+ printf("\tInput Sample Size: %s\n", iss[(vs & 0x20) >> 5]);
+ printf("\t# of bits padding at MSB: %d\n", (vs & 0x1c) >> 2);
+ }
+ printf("\tAir Coding Format: %s\n", acf[vs & 0x03]);
+ }
+}
+
+static int get_link_key(const bdaddr_t *local, const bdaddr_t *peer, uint8_t *key)
+{
+ char filename[PATH_MAX + 1], addr[18], tmp[3], *str;
+ int i;
+
+ ba2str(local, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "linkkeys");
+
+ ba2str(peer, addr);
+ str = textfile_get(filename, addr);
+ if (!str)
+ return -EIO;
+
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < 16; i++) {
+ memcpy(tmp, str + (i * 2), 2);
+ key[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ free(str);
+
+ return 0;
+}
+
+static void cmd_putkey(int ctl, int hdev, char *opt)
+{
+ struct hci_dev_info di;
+ bdaddr_t bdaddr;
+ uint8_t key[16];
+ int dd;
+
+ if (!opt)
+ return;
+
+ dd = hci_open_dev(hdev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (hci_devinfo(hdev, &di) < 0) {
+ fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ str2ba(opt, &bdaddr);
+ if (get_link_key(&di.bdaddr, &bdaddr, key) < 0) {
+ fprintf(stderr, "Can't find link key for %s on hci%d\n", opt, hdev);
+ exit(1);
+ }
+
+ if (hci_write_stored_link_key(dd, &bdaddr, key, 1000) < 0) {
+ fprintf(stderr, "Can't write stored link key on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_delkey(int ctl, int hdev, char *opt)
+{
+ bdaddr_t bdaddr;
+ uint8_t all;
+ 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);
+ all = 1;
+ } else {
+ str2ba(opt, &bdaddr);
+ all = 0;
+ }
+
+ if (hci_delete_stored_link_key(dd, &bdaddr, all, 1000) < 0) {
+ fprintf(stderr, "Can't delete stored link key on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_oob_data(int ctl, int hdev, char *opt)
+{
+ uint8_t hash[16], randomizer[16];
+ int i, dd;
+
+ dd = hci_open_dev(hdev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (hci_read_local_oob_data(dd, hash, randomizer, 1000) < 0) {
+ fprintf(stderr, "Can't read local OOB data on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tOOB Hash: ");
+ for (i = 0; i < 16; i++)
+ printf(" %02x", hash[i]);
+ printf("\n\tRandomizer:");
+ for (i = 0; i < 16; i++)
+ printf(" %02x", randomizer[i]);
+ printf("\n");
+
+ hci_close_dev(dd);
+}
+
+static void cmd_commands(int ctl, int hdev, char *opt)
+{
+ uint8_t cmds[64];
+ char *str;
+ int i, n, dd;
+
+ dd = hci_open_dev(hdev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (hci_read_local_commands(dd, cmds, 1000) < 0) {
+ fprintf(stderr, "Can't read support commands on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ for (i = 0; i < 64; i++) {
+ if (!cmds[i])
+ continue;
+
+ printf("%s Octet %-2d = 0x%02x (Bit",
+ i ? "\t\t ": "\tCommands:", i, cmds[i]);
+ for (n = 0; n < 8; n++)
+ if (cmds[i] & (1 << n))
+ printf(" %d", n);
+ printf(")\n");
+ }
+
+ str = hci_commandstostr(cmds, "\t", 71);
+ printf("%s\n", str);
+ bt_free(str);
+
+ hci_close_dev(dd);
+}
+
+static void cmd_version(int ctl, int hdev, char *opt)
+{
+ struct hci_version ver;
+ char *hciver, *lmpver;
+ int dd;
+
+ dd = hci_open_dev(hdev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (hci_read_local_version(dd, &ver, 1000) < 0) {
+ fprintf(stderr, "Can't read version info hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ hciver = hci_vertostr(ver.hci_ver);
+ 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"
+ "\tManufacturer: %s (%d)\n",
+ hciver ? hciver : "n/a", ver.hci_ver, ver.hci_rev,
+ lmpver ? lmpver : "n/a", ver.lmp_ver, ver.lmp_subver,
+ bt_compidtostr(ver.manufacturer), ver.manufacturer);
+
+ if (hciver)
+ bt_free(hciver);
+ if (lmpver)
+ bt_free(lmpver);
+
+ hci_close_dev(dd);
+}
+
+static void cmd_inq_tpl(int ctl, int hdev, char *opt)
+{
+ int dd;
+
+ 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 (opt) {
+ int8_t level = atoi(opt);
+
+ if (hci_write_inquiry_transmit_power_level(dd, level, 2000) < 0) {
+ fprintf(stderr, "Can't set inquiry transmit power level on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ int8_t level;
+
+ if (hci_read_inquiry_transmit_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);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tInquiry transmit power level: %d\n", level);
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_inq_mode(int ctl, int hdev, char *opt)
+{
+ int dd;
+
+ 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 (opt) {
+ uint8_t mode = atoi(opt);
+
+ if (hci_write_inquiry_mode(dd, mode, 2000) < 0) {
+ fprintf(stderr, "Can't set inquiry mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint8_t mode;
+
+ if (hci_read_inquiry_mode(dd, &mode, 1000) < 0) {
+ fprintf(stderr, "Can't read inquiry mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tInquiry mode: ");
+ switch (mode) {
+ case 0:
+ printf("Standard Inquiry\n");
+ break;
+ case 1:
+ printf("Inquiry with RSSI\n");
+ break;
+ case 2:
+ printf("Inquiry with RSSI or Extended Inquiry\n");
+ break;
+ default:
+ printf("Unknown (0x%02x)\n", mode);
+ break;
+ }
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_inq_data(int ctl, int hdev, char *opt)
+{
+ int i, dd;
+
+ 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 (opt) {
+ uint8_t fec = 0, data[240];
+ char tmp[3];
+ int i, size;
+
+ memset(data, 0, sizeof(data));
+
+ memset(tmp, 0, sizeof(tmp));
+ size = (strlen(opt) + 1) / 2;
+ if (size > 240)
+ size = 240;
+
+ for (i = 0; i < size; i++) {
+ memcpy(tmp, opt + (i * 2), 2);
+ data[i] = strtol(tmp, NULL, 16);
+ }
+
+ if (hci_write_ext_inquiry_response(dd, fec, data, 2000) < 0) {
+ fprintf(stderr, "Can't set extended inquiry response on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint8_t fec, data[240], len, type, *ptr;
+ char *str;
+
+ if (hci_read_ext_inquiry_response(dd, &fec, data, 1000) < 0) {
+ fprintf(stderr, "Can't read extended inquiry response on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tFEC %s\n\t\t", fec ? "enabled" : "disabled");
+ for (i = 0; i < 240; i++)
+ printf("%02x%s%s", data[i], (i + 1) % 8 ? "" : " ",
+ (i + 1) % 16 ? " " : (i < 239 ? "\n\t\t" : "\n"));
+
+ ptr = data;
+ while (*ptr) {
+ len = *ptr++;
+ type = *ptr++;
+ switch (type) {
+ case 0x01:
+ printf("\tFlags:");
+ for (i = 0; i < len - 1; i++)
+ printf(" 0x%2.2x", *((uint8_t *) (ptr + i)));
+ printf("\n");
+ break;
+ case 0x02:
+ case 0x03:
+ printf("\t%s service classes:",
+ type == 0x02 ? "Shortened" : "Complete");
+ for (i = 0; i < (len - 1) / 2; i++) {
+ uint16_t val = btohs(bt_get_unaligned((uint16_t *) (ptr + (i * 2))));
+ printf(" 0x%4.4x", val);
+ }
+ printf("\n");
+ break;
+ case 0x08:
+ case 0x09:
+ str = malloc(len);
+ if (str) {
+ snprintf(str, len, "%s", ptr);
+ for (i = 0; i < len - 1; i++) {
+ if ((unsigned char) str[i] < 32 || str[i] == 127)
+ str[i] = '.';
+ }
+ printf("\t%s local name: \'%s\'\n",
+ type == 0x08 ? "Shortened" : "Complete", str);
+ free(str);
+ }
+ break;
+ case 0x0a:
+ printf("\tTX power level: %d\n", *((uint8_t *) ptr));
+ break;
+ default:
+ printf("\tUnknown type 0x%02x with %d bytes data\n",
+ type, len - 1);
+ break;
+ }
+
+ ptr += (len - 1);
+ }
+
+ printf("\n");
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_inq_type(int ctl, int hdev, char *opt)
+{
+ int dd;
+
+ 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 (opt) {
+ uint8_t type = atoi(opt);
+
+ if (hci_write_inquiry_scan_type(dd, type, 2000) < 0) {
+ fprintf(stderr, "Can't set inquiry scan type on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint8_t type;
+
+ if (hci_read_inquiry_scan_type(dd, &type, 1000) < 0) {
+ fprintf(stderr, "Can't read inquiry scan type on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tInquiry scan type: %s\n",
+ type == 1 ? "Interlaced Inquiry Scan" : "Standard Inquiry Scan");
+ }
+
+ hci_close_dev(dd);
+}
+
+static void cmd_inq_parms(int ctl, int hdev, char *opt)
+{
+ struct hci_request rq;
+ int s;
+
+ if ((s = hci_open_dev(hdev)) < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ memset(&rq, 0, sizeof(rq));
+
+ if (opt) {
+ unsigned int window, interval;
+ write_inq_activity_cp cp;
+
+ if (sscanf(opt,"%4u:%4u", &window, &interval) != 2) {
+ printf("Invalid argument format\n");
+ exit(1);
+ }
+
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_WRITE_INQ_ACTIVITY;
+ rq.cparam = &cp;
+ rq.clen = WRITE_INQ_ACTIVITY_CP_SIZE;
+
+ cp.window = htobs((uint16_t) window);
+ cp.interval = htobs((uint16_t) interval);
+
+ if (window < 0x12 || window > 0x1000)
+ printf("Warning: inquiry window out of range!\n");
+
+ if (interval < 0x12 || interval > 0x1000)
+ printf("Warning: inquiry interval out of range!\n");
+
+ if (hci_send_req(s, &rq, 2000) < 0) {
+ fprintf(stderr, "Can't set inquiry parameters name on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint16_t window, interval;
+ read_inq_activity_rp rp;
+
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_READ_INQ_ACTIVITY;
+ rq.rparam = &rp;
+ rq.rlen = READ_INQ_ACTIVITY_RP_SIZE;
+
+ if (hci_send_req(s, &rq, 1000) < 0) {
+ fprintf(stderr, "Can't read inquiry parameters on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ if (rp.status) {
+ printf("Read inquiry parameters on hci%d returned status %d\n",
+ hdev, rp.status);
+ exit(1);
+ }
+ print_dev_hdr(&di);
+
+ window = btohs(rp.window);
+ interval = btohs(rp.interval);
+ printf("\tInquiry interval: %u slots (%.2f ms), window: %u slots (%.2f ms)\n",
+ interval, (float)interval * 0.625, window, (float)window * 0.625);
+ }
+}
+
+static void cmd_page_parms(int ctl, int hdev, char *opt)
+{
+ struct hci_request rq;
+ int s;
+
+ if ((s = hci_open_dev(hdev)) < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ memset(&rq, 0, sizeof(rq));
+
+ if (opt) {
+ unsigned int window, interval;
+ write_page_activity_cp cp;
+
+ if (sscanf(opt,"%4u:%4u", &window, &interval) != 2) {
+ printf("Invalid argument format\n");
+ exit(1);
+ }
+
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_WRITE_PAGE_ACTIVITY;
+ rq.cparam = &cp;
+ rq.clen = WRITE_PAGE_ACTIVITY_CP_SIZE;
+
+ cp.window = htobs((uint16_t) window);
+ cp.interval = htobs((uint16_t) interval);
+
+ if (window < 0x12 || window > 0x1000)
+ printf("Warning: page window out of range!\n");
+
+ if (interval < 0x12 || interval > 0x1000)
+ printf("Warning: page interval out of range!\n");
+
+ if (hci_send_req(s, &rq, 2000) < 0) {
+ fprintf(stderr, "Can't set page parameters name on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint16_t window, interval;
+ read_page_activity_rp rp;
+
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_READ_PAGE_ACTIVITY;
+ rq.rparam = &rp;
+ rq.rlen = READ_PAGE_ACTIVITY_RP_SIZE;
+
+ if (hci_send_req(s, &rq, 1000) < 0) {
+ fprintf(stderr, "Can't read page parameters on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ if (rp.status) {
+ printf("Read page parameters on hci%d returned status %d\n",
+ hdev, rp.status);
+ exit(1);
+ }
+ print_dev_hdr(&di);
+
+ window = btohs(rp.window);
+ interval = btohs(rp.interval);
+ printf("\tPage interval: %u slots (%.2f ms), window: %u slots (%.2f ms)\n",
+ interval, (float)interval * 0.625, window, (float)window * 0.625);
+ }
+}
+
+static void cmd_page_to(int ctl, int hdev, char *opt)
+{
+ struct hci_request rq;
+ int s;
+
+ if ((s = hci_open_dev(hdev)) < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ memset(&rq, 0, sizeof(rq));
+
+ if (opt) {
+ unsigned int timeout;
+ write_page_timeout_cp cp;
+
+ if (sscanf(opt,"%5u", &timeout) != 1) {
+ printf("Invalid argument format\n");
+ exit(1);
+ }
+
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_WRITE_PAGE_TIMEOUT;
+ rq.cparam = &cp;
+ rq.clen = WRITE_PAGE_TIMEOUT_CP_SIZE;
+
+ cp.timeout = htobs((uint16_t) timeout);
+
+ if (timeout < 0x01 || timeout > 0xFFFF)
+ printf("Warning: page timeout out of range!\n");
+
+ if (hci_send_req(s, &rq, 2000) < 0) {
+ fprintf(stderr, "Can't set page timeout on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint16_t timeout;
+ read_page_timeout_rp rp;
+
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_READ_PAGE_TIMEOUT;
+ rq.rparam = &rp;
+ rq.rlen = READ_PAGE_TIMEOUT_RP_SIZE;
+
+ if (hci_send_req(s, &rq, 1000) < 0) {
+ fprintf(stderr, "Can't read page timeout on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ if (rp.status) {
+ printf("Read page timeout on hci%d returned status %d\n",
+ hdev, rp.status);
+ exit(1);
+ }
+ print_dev_hdr(&di);
+
+ timeout = btohs(rp.timeout);
+ printf("\tPage timeout: %u slots (%.2f ms)\n",
+ timeout, (float)timeout * 0.625);
+ }
+}
+
+static void cmd_afh_mode(int ctl, int hdev, char *opt)
+{
+ int dd;
+
+ 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 (opt) {
+ uint8_t mode = atoi(opt);
+
+ if (hci_write_afh_mode(dd, mode, 2000) < 0) {
+ fprintf(stderr, "Can't set AFH mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint8_t mode;
+
+ if (hci_read_afh_mode(dd, &mode, 1000) < 0) {
+ fprintf(stderr, "Can't read AFH mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tAFH mode: %s\n", mode == 1 ? "Enabled" : "Disabled");
+ }
+}
+
+static void cmd_ssp_mode(int ctl, int hdev, char *opt)
+{
+ int dd;
+
+ 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 (opt) {
+ uint8_t mode = atoi(opt);
+
+ if (hci_write_simple_pairing_mode(dd, mode, 2000) < 0) {
+ fprintf(stderr, "Can't set Simple Pairing mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint8_t mode;
+
+ if (hci_read_simple_pairing_mode(dd, &mode, 1000) < 0) {
+ fprintf(stderr, "Can't read Simple Pairing mode on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tSimple Pairing mode: %s\n", mode == 1 ? "Enabled" : "Disabled");
+ }
+}
+
+static void print_rev_ericsson(int dd)
+{
+ struct hci_request rq;
+ unsigned char buf[102];
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x000f;
+ rq.cparam = NULL;
+ rq.clen = 0;
+ rq.rparam = &buf;
+ rq.rlen = sizeof(buf);
+
+ if (hci_send_req(dd, &rq, 1000) < 0) {
+ printf("\nCan't read revision info: %s (%d)\n", strerror(errno), errno);
+ return;
+ }
+
+ printf("\t%s\n", buf + 1);
+}
+
+static void print_rev_csr(int dd, uint16_t rev)
+{
+ uint16_t buildid, chipver, chiprev, maxkeylen, mapsco;
+
+ if (csr_read_varid_uint16(dd, 0, CSR_VARID_BUILDID, &buildid) < 0) {
+ printf("\t%s\n", csr_buildidtostr(rev));
+ return;
+ }
+
+ printf("\t%s\n", csr_buildidtostr(buildid));
+
+ if (!csr_read_varid_uint16(dd, 1, CSR_VARID_CHIPVER, &chipver)) {
+ if (csr_read_varid_uint16(dd, 2, CSR_VARID_CHIPREV, &chiprev) < 0)
+ chiprev = 0;
+ printf("\tChip version: %s\n", csr_chipvertostr(chipver, chiprev));
+ }
+
+ if (!csr_read_varid_uint16(dd, 3, CSR_VARID_MAX_CRYPT_KEY_LENGTH, &maxkeylen))
+ printf("\tMax key size: %d bit\n", maxkeylen * 8);
+
+ if (!csr_read_pskey_uint16(dd, 4, CSR_PSKEY_HOSTIO_MAP_SCO_PCM, 0x0000, &mapsco))
+ printf("\tSCO mapping: %s\n", mapsco ? "PCM" : "HCI");
+}
+
+static void print_rev_digianswer(int dd)
+{
+ struct hci_request rq;
+ unsigned char req[] = { 0x07 };
+ unsigned char buf[102];
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_VENDOR_CMD;
+ rq.ocf = 0x000e;
+ rq.cparam = req;
+ rq.clen = sizeof(req);
+ rq.rparam = &buf;
+ rq.rlen = sizeof(buf);
+
+ if (hci_send_req(dd, &rq, 1000) < 0) {
+ printf("\nCan't read revision info: %s (%d)\n", strerror(errno), errno);
+ return;
+ }
+
+ printf("\t%s\n", buf + 1);
+}
+
+static void print_rev_broadcom(uint16_t hci_rev, uint16_t lmp_subver)
+{
+ printf("\tFirmware %d.%d / %d\n", hci_rev & 0xff, lmp_subver >> 8, lmp_subver & 0xff);
+}
+
+static void print_rev_avm(uint16_t hci_rev, uint16_t lmp_subver)
+{
+ if (lmp_subver == 0x01)
+ printf("\tFirmware 03.%d.%d\n", hci_rev >> 8, hci_rev & 0xff);
+ else
+ printf("\tUnknown type\n");
+}
+
+static void cmd_revision(int ctl, int hdev, char *opt)
+{
+ struct hci_version ver;
+ int dd;
+
+ dd = hci_open_dev(hdev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ return;
+ }
+
+ if (hci_read_local_version(dd, &ver, 1000) < 0) {
+ fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ return;
+ }
+
+ print_dev_hdr(&di);
+ switch (ver.manufacturer) {
+ case 0:
+ case 37:
+ case 48:
+ print_rev_ericsson(dd);
+ break;
+ case 10:
+ print_rev_csr(dd, ver.hci_rev);
+ break;
+ case 12:
+ print_rev_digianswer(dd);
+ break;
+ case 15:
+ print_rev_broadcom(ver.hci_rev, ver.lmp_subver);
+ break;
+ case 31:
+ print_rev_avm(ver.hci_rev, ver.lmp_subver);
+ break;
+ default:
+ printf("\tUnsupported manufacturer\n");
+ break;
+ }
+ return;
+}
+
+static void print_dev_hdr(struct hci_dev_info *di)
+{
+ static int hdr = -1;
+ char addr[18];
+
+ if (hdr == di->dev_id)
+ return;
+ hdr = di->dev_id;
+
+ 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);
+}
+
+static void print_dev_info(int ctl, struct hci_dev_info *di)
+{
+ struct hci_dev_stats *st = &di->stat;
+
+ print_dev_hdr(di);
+
+ printf("\t%s\n", hci_dflagstostr(di->flags) );
+
+ printf("\tRX bytes:%d acl:%d sco:%d events:%d errors:%d\n",
+ st->byte_rx, st->acl_rx, st->sco_rx, st->evt_rx, st->err_rx);
+
+ printf("\tTX bytes:%d acl:%d sco:%d commands:%d errors:%d\n",
+ st->byte_tx, st->acl_tx, st->sco_tx, st->cmd_tx, st->err_tx);
+
+ if (all && !hci_test_bit(HCI_RAW, &di->flags) &&
+ bacmp(&di->bdaddr, BDADDR_ANY)) {
+ print_dev_features(di, 0);
+ print_pkt_type(di);
+ print_link_policy(di);
+ print_link_mode(di);
+
+ if (hci_test_bit(HCI_UP, &di->flags)) {
+ cmd_name(ctl, di->dev_id, NULL);
+ cmd_class(ctl, di->dev_id, NULL);
+ cmd_version(ctl, di->dev_id, NULL);
+ }
+ }
+
+ printf("\n");
+}
+
+static struct {
+ char *cmd;
+ void (*func)(int ctl, int hdev, char *opt);
+ char *opt;
+ char *doc;
+} command[] = {
+ { "up", cmd_up, 0, "Open and initialize HCI device" },
+ { "down", cmd_down, 0, "Close HCI device" },
+ { "reset", cmd_reset, 0, "Reset HCI device" },
+ { "rstat", cmd_rstat, 0, "Reset statistic counters" },
+ { "auth", cmd_auth, 0, "Enable Authentication" },
+ { "noauth", cmd_auth, 0, "Disable Authentication" },
+ { "encrypt", cmd_encrypt, 0, "Enable Encryption" },
+ { "noencrypt", cmd_encrypt, 0, "Disable Encryption" },
+ { "piscan", cmd_scan, 0, "Enable Page and Inquiry scan" },
+ { "noscan", cmd_scan, 0, "Disable scan" },
+ { "iscan", cmd_scan, 0, "Enable Inquiry scan" },
+ { "pscan", cmd_scan, 0, "Enable Page scan" },
+ { "ptype", cmd_ptype, "[type]", "Get/Set default packet type" },
+ { "lm", cmd_lm, "[mode]", "Get/Set default link mode" },
+ { "lp", cmd_lp, "[policy]", "Get/Set default link policy" },
+ { "name", cmd_name, "[name]", "Get/Set local name" },
+ { "class", cmd_class, "[class]", "Get/Set class of device" },
+ { "voice", cmd_voice, "[voice]", "Get/Set voice setting" },
+ { "iac", cmd_iac, "[iac]", "Get/Set inquiry access code" },
+ { "inqtpl", cmd_inq_tpl, "[level]", "Get/Set inquiry transmit power level" },
+ { "inqmode", cmd_inq_mode, "[mode]", "Get/Set inquiry mode" },
+ { "inqdata", cmd_inq_data, "[data]", "Get/Set inquiry data" },
+ { "inqtype", cmd_inq_type, "[type]", "Get/Set inquiry scan type" },
+ { "inqparms", cmd_inq_parms, "[win:int]", "Get/Set inquiry scan window and interval" },
+ { "pageparms", cmd_page_parms, "[win:int]", "Get/Set page scan window and interval" },
+ { "pageto", cmd_page_to, "[to]", "Get/Set page timeout" },
+ { "afhmode", cmd_afh_mode, "[mode]", "Get/Set AFH mode" },
+ { "sspmode", cmd_ssp_mode, "[mode]", "Get/Set Simple Pairing Mode" },
+ { "aclmtu", cmd_aclmtu, "<mtu:pkt>", "Set ACL MTU and number of packets" },
+ { "scomtu", cmd_scomtu, "<mtu:pkt>", "Set SCO MTU and number of packets" },
+ { "putkey", cmd_putkey, "<bdaddr>", "Store link key on the device" },
+ { "delkey", cmd_delkey, "<bdaddr>", "Delete link key from the device" },
+ { "oobdata", cmd_oob_data, 0, "Display local OOB data" },
+ { "commands", cmd_commands, 0, "Display supported commands" },
+ { "features", cmd_features, 0, "Display device features" },
+ { "version", cmd_version, 0, "Display version information" },
+ { "revision", cmd_revision, 0, "Display revision information" },
+ { NULL, NULL, 0 }
+};
+
+static void usage(void)
+{
+ int i;
+
+ printf("hciconfig - HCI device configuration utility\n");
+ printf("Usage:\n"
+ "\thciconfig\n"
+ "\thciconfig [-a] hciX [command]\n");
+ printf("Commands:\n");
+ for (i=0; command[i].cmd; i++)
+ printf("\t%-10s %-8s\t%s\n", command[i].cmd,
+ command[i].opt ? command[i].opt : " ",
+ command[i].doc);
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "all", 0, 0, 'a' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ int opt, ctl, i, cmd=0;
+
+ while ((opt=getopt_long(argc, argv, "ah", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'a':
+ all = 1;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ /* Open HCI socket */
+ if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
+ perror("Can't open HCI socket.");
+ exit(1);
+ }
+
+ if (argc < 1) {
+ print_dev_list(ctl, 0);
+ exit(0);
+ }
+
+ di.dev_id = atoi(argv[0] + 3);
+ argc--; argv++;
+
+ if (ioctl(ctl, HCIGETDEVINFO, (void *) &di)) {
+ perror("Can't get device info");
+ exit(1);
+ }
+
+ if (hci_test_bit(HCI_RAW, &di.flags) &&
+ !bacmp(&di.bdaddr, BDADDR_ANY)) {
+ int dd = hci_open_dev(di.dev_id);
+ hci_read_bd_addr(dd, &di.bdaddr, 1000);
+ hci_close_dev(dd);
+ }
+
+ while (argc > 0) {
+ for (i = 0; command[i].cmd; i++) {
+ if (strncmp(command[i].cmd, *argv, 5))
+ continue;
+
+ if (command[i].opt) {
+ argc--; argv++;
+ }
+
+ command[i].func(ctl, di.dev_id, *argv);
+ cmd = 1;
+ break;
+ }
+ argc--; argv++;
+ }
+
+ if (!cmd)
+ print_dev_info(ctl, &di);
+
+ close(ctl);
+ return 0;
+}
diff --git a/utils/tools/hcisecfilter.c b/utils/tools/hcisecfilter.c
new file mode 100644
index 00000000..81a2fca4
--- /dev/null
+++ b/utils/tools/hcisecfilter.c
@@ -0,0 +1,155 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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 <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+int main(void)
+{
+ uint32_t type_mask;
+ uint32_t event_mask[2];
+ uint32_t ocf_mask[4];
+
+ /* Packet types */
+ memset(&type_mask, 0, sizeof(type_mask));
+ hci_set_bit(HCI_EVENT_PKT, &type_mask);
+
+ printf("Type mask: { 0x%02x }\n", type_mask);
+
+ /* Events */
+ memset(event_mask, 0, sizeof(event_mask));
+ hci_set_bit(EVT_INQUIRY_COMPLETE, event_mask);
+ hci_set_bit(EVT_INQUIRY_RESULT, event_mask);
+ hci_set_bit(EVT_CONN_COMPLETE, event_mask);
+ hci_set_bit(EVT_CONN_REQUEST, event_mask);
+ hci_set_bit(EVT_DISCONN_COMPLETE, event_mask);
+ hci_set_bit(EVT_AUTH_COMPLETE, event_mask);
+ hci_set_bit(EVT_REMOTE_NAME_REQ_COMPLETE, event_mask);
+ hci_set_bit(EVT_ENCRYPT_CHANGE, event_mask);
+ hci_set_bit(EVT_READ_REMOTE_FEATURES_COMPLETE, event_mask);
+ hci_set_bit(EVT_READ_REMOTE_VERSION_COMPLETE, event_mask);
+ hci_set_bit(EVT_CMD_COMPLETE, event_mask);
+ hci_set_bit(EVT_CMD_STATUS, event_mask);
+ hci_set_bit(EVT_READ_CLOCK_OFFSET_COMPLETE, event_mask);
+ hci_set_bit(EVT_INQUIRY_RESULT_WITH_RSSI, event_mask);
+ hci_set_bit(EVT_READ_REMOTE_EXT_FEATURES_COMPLETE, event_mask);
+ hci_set_bit(EVT_SYNC_CONN_COMPLETE, event_mask);
+ hci_set_bit(EVT_SYNC_CONN_CHANGED, event_mask);
+ hci_set_bit(EVT_EXTENDED_INQUIRY_RESULT, event_mask);
+
+ printf("Event mask: { 0x%08x, 0x%08x }\n",
+ event_mask[0], event_mask[1]);
+
+ /* OGF_LINK_CTL */
+ memset(ocf_mask, 0, sizeof(ocf_mask));
+ hci_set_bit(OCF_INQUIRY, ocf_mask);
+ hci_set_bit(OCF_INQUIRY_CANCEL, ocf_mask);
+ hci_set_bit(OCF_REMOTE_NAME_REQ, ocf_mask);
+ hci_set_bit(OCF_REMOTE_NAME_REQ_CANCEL, ocf_mask);
+ hci_set_bit(OCF_READ_REMOTE_FEATURES, ocf_mask);
+ hci_set_bit(OCF_READ_REMOTE_EXT_FEATURES, ocf_mask);
+ hci_set_bit(OCF_READ_REMOTE_VERSION, ocf_mask);
+ hci_set_bit(OCF_READ_CLOCK_OFFSET, ocf_mask);
+ hci_set_bit(OCF_READ_LMP_HANDLE, ocf_mask);
+
+ printf("OGF_LINK_CTL: { 0x%08x, 0x%08x, 0x%08x, 0x%02x }\n",
+ ocf_mask[0], ocf_mask[1], ocf_mask[2], ocf_mask[3]);
+
+ /* OGF_LINK_POLICY */
+ memset(ocf_mask, 0, sizeof(ocf_mask));
+ hci_set_bit(OCF_ROLE_DISCOVERY, ocf_mask);
+ hci_set_bit(OCF_READ_LINK_POLICY, ocf_mask);
+ hci_set_bit(OCF_READ_DEFAULT_LINK_POLICY, ocf_mask);
+
+ printf("OGF_LINK_POLICY: { 0x%08x, 0x%08x, 0x%08x, 0x%02x }\n",
+ ocf_mask[0], ocf_mask[1], ocf_mask[2], ocf_mask[3]);
+
+ /* OGF_HOST_CTL */
+ memset(ocf_mask, 0, sizeof(ocf_mask));
+ hci_set_bit(OCF_READ_PIN_TYPE, ocf_mask);
+ hci_set_bit(OCF_READ_LOCAL_NAME, ocf_mask);
+ hci_set_bit(OCF_READ_CONN_ACCEPT_TIMEOUT, ocf_mask);
+ hci_set_bit(OCF_READ_PAGE_TIMEOUT, ocf_mask);
+ hci_set_bit(OCF_READ_SCAN_ENABLE, ocf_mask);
+ hci_set_bit(OCF_READ_PAGE_ACTIVITY, ocf_mask);
+ hci_set_bit(OCF_READ_INQ_ACTIVITY, ocf_mask);
+ hci_set_bit(OCF_READ_AUTH_ENABLE, ocf_mask);
+ hci_set_bit(OCF_READ_ENCRYPT_MODE, ocf_mask);
+ hci_set_bit(OCF_READ_CLASS_OF_DEV, ocf_mask);
+ hci_set_bit(OCF_READ_VOICE_SETTING, ocf_mask);
+ hci_set_bit(OCF_READ_AUTOMATIC_FLUSH_TIMEOUT, ocf_mask);
+ hci_set_bit(OCF_READ_NUM_BROADCAST_RETRANS, ocf_mask);
+ hci_set_bit(OCF_READ_HOLD_MODE_ACTIVITY, ocf_mask);
+ hci_set_bit(OCF_READ_TRANSMIT_POWER_LEVEL, ocf_mask);
+ hci_set_bit(OCF_READ_LINK_SUPERVISION_TIMEOUT, ocf_mask);
+ hci_set_bit(OCF_READ_NUM_SUPPORTED_IAC, ocf_mask);
+ hci_set_bit(OCF_READ_CURRENT_IAC_LAP, ocf_mask);
+ hci_set_bit(OCF_READ_PAGE_SCAN_PERIOD_MODE, ocf_mask);
+ hci_set_bit(OCF_READ_PAGE_SCAN_MODE, ocf_mask);
+ hci_set_bit(OCF_READ_INQUIRY_SCAN_TYPE, ocf_mask);
+ hci_set_bit(OCF_READ_INQUIRY_MODE, ocf_mask);
+ hci_set_bit(OCF_READ_PAGE_SCAN_TYPE, ocf_mask);
+ 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_DEFAULT_ERROR_DATA_REPORTING, ocf_mask);
+
+ printf("OGF_HOST_CTL: { 0x%08x, 0x%08x, 0x%08x, 0x%02x }\n",
+ ocf_mask[0], ocf_mask[1], ocf_mask[2], ocf_mask[3]);
+
+ /* OGF_INFO_PARAM */
+ memset(ocf_mask, 0, sizeof(ocf_mask));
+ hci_set_bit(OCF_READ_LOCAL_VERSION, ocf_mask);
+ hci_set_bit(OCF_READ_LOCAL_COMMANDS, ocf_mask);
+ hci_set_bit(OCF_READ_LOCAL_FEATURES, ocf_mask);
+ hci_set_bit(OCF_READ_LOCAL_EXT_FEATURES, ocf_mask);
+ hci_set_bit(OCF_READ_BUFFER_SIZE, ocf_mask);
+ hci_set_bit(OCF_READ_COUNTRY_CODE, ocf_mask);
+ hci_set_bit(OCF_READ_BD_ADDR, ocf_mask);
+
+ printf("OGF_INFO_PARAM: { 0x%08x, 0x%08x, 0x%08x, 0x%02x }\n",
+ ocf_mask[0], ocf_mask[1], ocf_mask[2], ocf_mask[3]);
+
+ /* OGF_STATUS_PARAM */
+ memset(ocf_mask, 0, sizeof(ocf_mask));
+ hci_set_bit(OCF_READ_FAILED_CONTACT_COUNTER, ocf_mask);
+ hci_set_bit(OCF_READ_LINK_QUALITY, ocf_mask);
+ hci_set_bit(OCF_READ_RSSI, ocf_mask);
+ hci_set_bit(OCF_READ_AFH_MAP, ocf_mask);
+ hci_set_bit(OCF_READ_CLOCK, ocf_mask);
+
+ printf("OGF_STATUS_PARAM: { 0x%08x, 0x%08x, 0x%08x, 0x%02x }\n",
+ ocf_mask[0], ocf_mask[1], ocf_mask[2], ocf_mask[3]);
+
+ return 0;
+}
diff --git a/utils/tools/hcitool.1 b/utils/tools/hcitool.1
new file mode 100644
index 00000000..8a7131d2
--- /dev/null
+++ b/utils/tools/hcitool.1
@@ -0,0 +1,206 @@
+.TH HCITOOL 1 "Nov 12 2002" BlueZ "Linux System Administration"
+.SH NAME
+hcitool \- configure Bluetooth connections
+.SH SYNOPSIS
+.B hcitool [-h]
+.br
+.B hcitool [-i <hciX>] [command [command parameters]]
+
+.SH DESCRIPTION
+.LP
+.B
+hcitool
+is used to configure Bluetooth connections and send some special command to
+Bluetooth devices. If no
+.B
+command
+is given, or if the option
+.B
+-h
+is used,
+.B
+hcitool
+prints some usage information and exits.
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible commands
+.TP
+.BI -i " <hciX>"
+The command is applied to device
+.I
+hciX
+, which must be the name of an installed Bluetooth device. If not specified,
+the command will be sent to the first available Bluetooth device.
+.SH COMMANDS
+.TP
+.BI dev
+Display local devices
+.TP
+.BI inq
+Inquire remote devices. For each discovered device, Bluetooth device address,
+clock offset and class are printed.
+.TP
+.BI scan
+Inquire remote devices. For each discovered device, device name are printed.
+.TP
+.BI name " <bdaddr>"
+Print device name of remote device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI info " <bdaddr>"
+Print device name, version and supported features of remote device with
+Bluetooth address
+.IR bdaddr .
+.TP
+.BI spinq
+Start periodic inquiry process. No inquiry results are printed.
+.TP
+.BI epinq
+Exit periodic inquiry process.
+.TP
+.BI cmd " <ogf> <ocf> [parameters]"
+Submit an arbitrary HCI command to local device.
+.IR ogf ,
+.IR ocf
+and
+.IR parameters
+are hexadecimal bytes.
+.TP
+.BI con
+Display active baseband connections
+.TP
+.BI cc " [--role=m|s] [--pkt-type=<ptype>] <bdaddr>"
+Create baseband connection to remote device with Bluetooth address
+.IR bdaddr .
+Option
+.I
+--pkt-type
+specifies a list of allowed packet types.
+.I
+<ptype>
+is a comma-separated list of packet types, where the possible packet types are
+.BR DM1 ,
+.BR DM3 ,
+.BR DM5 ,
+.BR DH1 ,
+.BR DH3 ,
+.BR DH5 ,
+.BR HV1 ,
+.BR HV2 ,
+.BR HV3 .
+Default is to allow all packet types. Option
+.I
+--role
+can have value
+.I
+m
+(do not allow role switch, stay master) or
+.I
+s
+(allow role switch, become slave if the peer asks to become master). Default is
+.IR m .
+.TP
+.BI dc " <bdaddr>"
+Delete baseband connection from remote device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI sr " <bdaddr> <role>"
+Switch role for the baseband connection from the remote device to
+.BR master
+or
+.BR slave .
+.TP
+.BI cpt " <bdaddr> <packet types>"
+Change packet types for baseband connection to device with Bluetooth address
+.IR bdaddr .
+.I
+packet types
+is a comma-separated list of packet types, where the possible packet types are
+.BR DM1 ,
+.BR DM3 ,
+.BR DM5 ,
+.BR DH1 ,
+.BR DH3 ,
+.BR DH5 ,
+.BR HV1 ,
+.BR HV2 ,
+.BR HV3 .
+.TP
+.BI rssi " <bdaddr>"
+Display received signal strength information for the connection to the device
+with Bluetooth address
+.IR bdaddr .
+.TP
+.BI lq " <bdaddr>"
+Display link quality for the connection to the device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI tpl " <bdaddr> [type]"
+Display transmit power level for the connection to the device with Bluetooth address
+.IR bdaddr .
+The type can be
+.BR 0
+for the current transmit power level (which is default) or
+.BR 1
+for the maximum transmit power level.
+.TP
+.BI afh " <bdaddr>"
+Display AFH channel map for the connection to the device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI lp " <bdaddr> [value]"
+With no
+.IR value ,
+displays link policy settings for the connection to the device with Bluetooth address
+.IR bdaddr .
+If
+.IR value
+is given, sets the link policy settings for that connection to
+.IR value .
+Possible values are RSWITCH, HOLD, SNIFF and PARK.
+.TP
+.BI lst " <bdaddr> [value]"
+With no
+.IR value ,
+displays link supervision timeout for the connection to the device with Bluetooth address
+.IR bdaddr .
+If
+.I
+value
+is given, sets the link supervision timeout for that connection to
+.I
+value
+slots, or to infinite if
+.I
+value
+is 0.
+.TP
+.BI auth " <bdaddr>"
+Request authentication for the device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI enc " <bdaddr> [encrypt enable]"
+Enable or disable the encryption for the device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI key " <bdaddr>"
+Change the connection link key for the device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI clkoff " <bdaddr>"
+Read the clock offset for the device with Bluetooth address
+.IR bdaddr .
+.TP
+.BI clock " [bdaddr] [which clock]"
+Read the clock for the device with Bluetooth address
+.IR bdaddr .
+The clock can be
+.BR 0
+for the local clock or
+.BR 1
+for the piconet clock (which is default).
+.SH AUTHORS
+Written by Maxim Krasnyansky <maxk@qualcomm.com> and Marcel Holtmann <marcel@holtmann.org>
+.PP
+man page by Fabrizio Gennari <fabrizio.gennari@philips.com>
diff --git a/utils/tools/hcitool.c b/utils/tools/hcitool.c
new file mode 100644
index 00000000..02f56a43
--- /dev/null
+++ b/utils/tools/hcitool.c
@@ -0,0 +1,2435 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "textfile.h"
+#include "oui.h"
+
+#define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, NULL)) != -1)
+
+static void usage(void);
+
+static int dev_info(int s, int dev_id, long arg)
+{
+ struct hci_dev_info di = { dev_id: dev_id };
+ char addr[18];
+
+ if (ioctl(s, HCIGETDEVINFO, (void *) &di))
+ return 0;
+
+ ba2str(&di.bdaddr, addr);
+ printf("\t%s\t%s\n", di.name, addr);
+ return 0;
+}
+
+static char *type2str(uint8_t type)
+{
+ switch (type) {
+ case SCO_LINK:
+ return "SCO";
+ case ACL_LINK:
+ return "ACL";
+ case ESCO_LINK:
+ return "eSCO";
+ default:
+ return "Unknown";
+ }
+}
+
+static int conn_list(int s, int dev_id, long arg)
+{
+ struct hci_conn_list_req *cl;
+ struct hci_conn_info *ci;
+ int id = arg;
+ int i;
+
+ if (id != -1 && dev_id != id)
+ return 0;
+
+ if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+ cl->dev_id = dev_id;
+ cl->conn_num = 10;
+ ci = cl->conn_info;
+
+ if (ioctl(s, HCIGETCONNLIST, (void *) cl)) {
+ perror("Can't get connection list");
+ exit(1);
+ }
+
+ for (i = 0; i < cl->conn_num; i++, ci++) {
+ char addr[18];
+ ba2str(&ci->bdaddr, addr);
+ printf("\t%s %s %s handle %d state %d lm %s\n",
+ ci->out ? "<" : ">", type2str(ci->type),
+ addr, ci->handle, ci->state,
+ hci_lmtostr(ci->link_mode));
+ }
+
+ return 0;
+}
+
+static int find_conn(int s, int dev_id, long arg)
+{
+ struct hci_conn_list_req *cl;
+ struct hci_conn_info *ci;
+ int i;
+
+ if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+ cl->dev_id = dev_id;
+ cl->conn_num = 10;
+ ci = cl->conn_info;
+
+ if (ioctl(s, HCIGETCONNLIST, (void *) cl)) {
+ perror("Can't get connection list");
+ exit(1);
+ }
+
+ for (i = 0; i < cl->conn_num; i++, ci++)
+ if (!bacmp((bdaddr_t *) arg, &ci->bdaddr))
+ return 1;
+
+ return 0;
+}
+
+static void hex_dump(char *pref, int width, unsigned char *buf, int len)
+{
+ register int i,n;
+
+ for (i = 0, n = 1; i < len; i++, n++) {
+ if (n == 1)
+ printf("%s", pref);
+ printf("%2.2X ", buf[i]);
+ if (n == width) {
+ printf("\n");
+ n = 0;
+ }
+ }
+ if (i && n!=1)
+ printf("\n");
+}
+
+static char *get_minor_device_name(int major, int minor)
+{
+ switch (major) {
+ case 0: /* misc */
+ return "";
+ case 1: /* computer */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Desktop workstation";
+ case 2:
+ return "Server";
+ case 3:
+ return "Laptop";
+ case 4:
+ return "Handheld";
+ case 5:
+ return "Palm";
+ case 6:
+ return "Wearable";
+ }
+ break;
+ case 2: /* phone */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Cellular";
+ case 2:
+ return "Cordless";
+ case 3:
+ return "Smart phone";
+ case 4:
+ return "Wired modem or voice gateway";
+ case 5:
+ return "Common ISDN Access";
+ case 6:
+ return "Sim Card Reader";
+ }
+ break;
+ case 3: /* lan access */
+ if (minor == 0)
+ return "Uncategorized";
+ switch(minor / 8) {
+ case 0:
+ return "Fully available";
+ case 1:
+ return "1-17% utilized";
+ case 2:
+ return "17-33% utilized";
+ case 3:
+ return "33-50% utilized";
+ case 4:
+ return "50-67% utilized";
+ case 5:
+ return "67-83% utilized";
+ case 6:
+ return "83-99% utilized";
+ case 7:
+ return "No service available";
+ }
+ break;
+ case 4: /* audio/video */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Device conforms to the Headset profile";
+ case 2:
+ return "Hands-free";
+ /* 3 is reserved */
+ case 4:
+ return "Microphone";
+ case 5:
+ return "Loudspeaker";
+ case 6:
+ return "Headphones";
+ case 7:
+ return "Portable Audio";
+ case 8:
+ return "Car Audio";
+ case 9:
+ return "Set-top box";
+ case 10:
+ return "HiFi Audio Device";
+ case 11:
+ return "VCR";
+ case 12:
+ return "Video Camera";
+ case 13:
+ return "Camcorder";
+ case 14:
+ return "Video Monitor";
+ case 15:
+ return "Video Display and Loudspeaker";
+ case 16:
+ return "Video Conferencing";
+ /* 17 is reserved */
+ case 18:
+ return "Gaming/Toy";
+ }
+ break;
+ case 5: /* peripheral */ {
+ static char cls_str[48]; cls_str[0] = 0;
+
+ switch(minor & 48) {
+ case 16:
+ strncpy(cls_str, "Keyboard", sizeof(cls_str));
+ break;
+ case 32:
+ strncpy(cls_str, "Pointing device", sizeof(cls_str));
+ break;
+ case 48:
+ strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str));
+ break;
+ }
+ if((minor & 15) && (strlen(cls_str) > 0))
+ strcat(cls_str, "/");
+
+ switch(minor & 15) {
+ case 0:
+ break;
+ case 1:
+ strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 2:
+ strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 3:
+ strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 4:
+ strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 5:
+ strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str));
+ break;
+ case 6:
+ strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str));
+ break;
+ default:
+ strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str));
+ break;
+ }
+ if(strlen(cls_str) > 0)
+ return cls_str;
+ }
+ case 6: /* imaging */
+ if (minor & 4)
+ return "Display";
+ if (minor & 8)
+ return "Camera";
+ if (minor & 16)
+ return "Scanner";
+ if (minor & 32)
+ return "Printer";
+ break;
+ case 7: /* wearable */
+ switch(minor) {
+ case 1:
+ return "Wrist Watch";
+ case 2:
+ return "Pager";
+ case 3:
+ return "Jacket";
+ case 4:
+ return "Helmet";
+ case 5:
+ return "Glasses";
+ }
+ break;
+ case 8: /* toy */
+ switch(minor) {
+ case 1:
+ return "Robot";
+ case 2:
+ return "Vehicle";
+ case 3:
+ return "Doll / Action Figure";
+ case 4:
+ return "Controller";
+ case 5:
+ return "Game";
+ }
+ break;
+ case 63: /* uncategorised */
+ return "";
+ }
+ return "Unknown (reserved) minor device class";
+}
+
+static char *major_classes[] = {
+ "Miscellaneous", "Computer", "Phone", "LAN Access",
+ "Audio/Video", "Peripheral", "Imaging", "Uncategorized"
+};
+
+static char *get_device_name(const bdaddr_t *local, const bdaddr_t *peer)
+{
+ char filename[PATH_MAX + 1], addr[18];
+
+ ba2str(local, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "names");
+
+ ba2str(peer, addr);
+ return textfile_get(filename, addr);
+}
+
+/* Display local devices */
+
+static struct option dev_options[] = {
+ { "help", 0, 0, 'h' },
+ {0, 0, 0, 0 }
+};
+
+static char *dev_help =
+ "Usage:\n"
+ "\tdev\n";
+
+static void cmd_dev(int dev_id, int argc, char **argv)
+{
+ int opt;
+
+ for_each_opt(opt, dev_options, NULL) {
+ switch (opt) {
+ default:
+ printf(dev_help);
+ return;
+ }
+ }
+
+ printf("Devices:\n");
+
+ hci_for_each_dev(HCI_UP, dev_info, 0);
+}
+
+/* Inquiry */
+
+static struct option inq_options[] = {
+ { "help", 0, 0, 'h' },
+ { "length", 1, 0, 'l' },
+ { "numrsp", 1, 0, 'n' },
+ { "iac", 1, 0, 'i' },
+ { "flush", 0, 0, 'f' },
+ { 0, 0, 0, 0 }
+};
+
+static char *inq_help =
+ "Usage:\n"
+ "\tinq [--length=N] maximum inquiry duration in 1.28 s units\n"
+ "\t [--numrsp=N] specify maximum number of inquiry responses\n"
+ "\t [--iac=lap] specify the inquiry access code\n"
+ "\t [--flush] flush the inquiry cache\n";
+
+static void cmd_inq(int dev_id, int argc, char **argv)
+{
+ inquiry_info *info = NULL;
+ uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
+ int num_rsp, length, flags;
+ char addr[18];
+ int i, l, opt;
+
+ length = 8; /* ~10 seconds */
+ num_rsp = 0;
+ flags = 0;
+
+ for_each_opt(opt, inq_options, NULL) {
+ switch (opt) {
+ case 'l':
+ length = atoi(optarg);
+ break;
+
+ case 'n':
+ num_rsp = atoi(optarg);
+ break;
+
+ case 'i':
+ l = strtoul(optarg, 0, 16);
+ if (!strcasecmp(optarg, "giac")) {
+ l = 0x9e8b33;
+ } else if (!strcasecmp(optarg, "liac")) {
+ l = 0x9e8b00;
+ } if (l < 0x9e8b00 || l > 0x9e8b3f) {
+ printf("Invalid access code 0x%x\n", l);
+ exit(1);
+ }
+ lap[0] = (l & 0xff);
+ lap[1] = (l >> 8) & 0xff;
+ lap[2] = (l >> 16) & 0xff;
+ break;
+
+ case 'f':
+ flags |= IREQ_CACHE_FLUSH;
+ break;
+
+ default:
+ printf(inq_help);
+ return;
+ }
+ }
+
+ printf("Inquiring ...\n");
+
+ num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &info, flags);
+ if (num_rsp < 0) {
+ perror("Inquiry failed.");
+ exit(1);
+ }
+
+ for (i = 0; i < num_rsp; i++) {
+ ba2str(&(info+i)->bdaddr, addr);
+ printf("\t%s\tclock offset: 0x%4.4x\tclass: 0x%2.2x%2.2x%2.2x\n",
+ addr, btohs((info+i)->clock_offset),
+ (info+i)->dev_class[2],
+ (info+i)->dev_class[1],
+ (info+i)->dev_class[0]);
+ }
+
+ bt_free(info);
+}
+
+/* Device scanning */
+
+static struct option scan_options[] = {
+ { "help", 0, 0, 'h' },
+ { "length", 1, 0, 'l' },
+ { "numrsp", 1, 0, 'n' },
+ { "iac", 1, 0, 'i' },
+ { "flush", 0, 0, 'f' },
+ { "refresh", 0, 0, 'r' },
+ { "class", 0, 0, 'C' },
+ { "info", 0, 0, 'I' },
+ { "oui", 0, 0, 'O' },
+ { "all", 0, 0, 'A' },
+ { "ext", 0, 0, 'A' },
+ { 0, 0, 0, 0 }
+};
+
+static char *scan_help =
+ "Usage:\n"
+ "\tscan [--length=N] [--numrsp=N] [--iac=lap] [--flush] [--class] [--info] [--oui] [--refresh]\n";
+
+static void cmd_scan(int dev_id, int argc, char **argv)
+{
+ inquiry_info *info = NULL;
+ 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;
+ struct hci_conn_info_req *cr;
+ int refresh = 0, extcls = 0, extinf = 0, extoui = 0;
+ int i, n, l, opt, dd, cc, nc;
+
+ length = 8; /* ~10 seconds */
+ num_rsp = 0;
+ flags = 0;
+
+ for_each_opt(opt, scan_options, NULL) {
+ switch (opt) {
+ case 'l':
+ length = atoi(optarg);
+ break;
+
+ case 'n':
+ num_rsp = atoi(optarg);
+ break;
+
+ case 'i':
+ l = strtoul(optarg, 0, 16);
+ if (!strcasecmp(optarg, "giac")) {
+ l = 0x9e8b33;
+ } else if (!strcasecmp(optarg, "liac")) {
+ l = 0x9e8b00;
+ } else if (l < 0x9e8b00 || l > 0x9e8b3f) {
+ printf("Invalid access code 0x%x\n", l);
+ exit(1);
+ }
+ lap[0] = (l & 0xff);
+ lap[1] = (l >> 8) & 0xff;
+ lap[2] = (l >> 16) & 0xff;
+ break;
+
+ case 'f':
+ flags |= IREQ_CACHE_FLUSH;
+ break;
+
+ case 'r':
+ refresh = 1;
+ break;
+
+ case 'C':
+ extcls = 1;
+ break;
+
+ case 'I':
+ extinf = 1;
+ break;
+
+ case 'O':
+ extoui = 1;
+ break;
+
+ case 'A':
+ extcls = 1;
+ extinf = 1;
+ extoui = 1;
+ break;
+
+ default:
+ printf(scan_help);
+ return;
+ }
+ }
+
+ if (dev_id < 0) {
+ dev_id = hci_get_route(NULL);
+ if (dev_id < 0) {
+ perror("Device is not available");
+ exit(1);
+ }
+ }
+
+ if (hci_devinfo(dev_id, &di) < 0) {
+ perror("Can't get device info");
+ exit(1);
+ }
+
+ printf("Scanning ...\n");
+ num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &info, flags);
+ if (num_rsp < 0) {
+ perror("Inquiry failed");
+ exit(1);
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ free(info);
+ exit(1);
+ }
+
+ if (extcls || extinf || extoui)
+ printf("\n");
+
+ for (i = 0; i < num_rsp; i++) {
+ if (!refresh) {
+ memset(name, 0, sizeof(name));
+ tmp = get_device_name(&di.bdaddr, &(info+i)->bdaddr);
+ if (tmp) {
+ strncpy(name, tmp, 249);
+ free(tmp);
+ nc = 1;
+ } else
+ nc = 0;
+ } else
+ nc = 0;
+
+ if (!extcls && !extinf && !extoui) {
+ ba2str(&(info+i)->bdaddr, addr);
+
+ if (nc) {
+ printf("\t%s\t%s\n", addr, name);
+ continue;
+ }
+
+ if (hci_read_remote_name_with_clock_offset(dd,
+ &(info+i)->bdaddr,
+ (info+i)->pscan_rep_mode,
+ (info+i)->clock_offset | 0x8000,
+ sizeof(name), name, 100000) < 0)
+ strcpy(name, "n/a");
+
+ for (n = 0; n < 248 && name[n]; n++) {
+ if ((unsigned char) name[i] < 32 || name[i] == 127)
+ name[i] = '.';
+ }
+
+ name[248] = '\0';
+
+ printf("\t%s\t%s\n", addr, name);
+ continue;
+ }
+
+ ba2str(&(info+i)->bdaddr, addr);
+ printf("BD Address:\t%s [mode %d, clkoffset 0x%4.4x]\n", addr,
+ (info+i)->pscan_rep_mode, btohs((info+i)->clock_offset));
+
+ if (extoui) {
+ ba2oui(&(info+i)->bdaddr, oui);
+ comp = ouitocomp(oui);
+ if (comp) {
+ printf("OUI company:\t%s (%s)\n", comp, oui);
+ free(comp);
+ }
+ }
+
+ cc = 0;
+
+ if (extinf) {
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (cr) {
+ bacpy(&cr->bdaddr, &(info+i)->bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ handle = 0;
+ cc = 1;
+ } else {
+ handle = htobs(cr->conn_info->handle);
+ cc = 0;
+ }
+ free(cr);
+ }
+
+ if (cc) {
+ if (hci_create_connection(dd, &(info+i)->bdaddr,
+ htobs(di.pkt_type & ACL_PTYPE_MASK),
+ (info+i)->clock_offset | 0x8000,
+ 0x01, &handle, 25000) < 0) {
+ handle = 0;
+ cc = 0;
+ }
+ }
+ }
+
+ if (handle > 0 || !nc) {
+ if (hci_read_remote_name_with_clock_offset(dd,
+ &(info+i)->bdaddr,
+ (info+i)->pscan_rep_mode,
+ (info+i)->clock_offset | 0x8000,
+ sizeof(name), name, 100000) < 0) {
+ if (!nc)
+ strcpy(name, "n/a");
+ } else {
+ for (n = 0; n < 248 && name[n]; n++) {
+ if ((unsigned char) name[i] < 32 || name[i] == 127)
+ name[i] = '.';
+ }
+
+ name[248] = '\0';
+ nc = 0;
+ }
+ }
+
+ if (strlen(name) > 0)
+ printf("Device name:\t%s%s\n", name, nc ? " [cached]" : "");
+
+ if (extcls) {
+ memcpy(cls, (info+i)->dev_class, 3);
+ printf("Device class:\t");
+ if ((cls[1] & 0x1f) > sizeof(major_classes) / sizeof(char *))
+ printf("Invalid");
+ else
+ printf("%s, %s", major_classes[cls[1] & 0x1f],
+ get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2));
+ printf(" (0x%2.2x%2.2x%2.2x)\n", cls[2], cls[1], cls[0]);
+ }
+
+ if (extinf && handle > 0) {
+ if (hci_read_remote_version(dd, handle, &version, 20000) == 0) {
+ char *ver = lmp_vertostr(version.lmp_ver);
+ printf("Manufacturer:\t%s (%d)\n",
+ bt_compidtostr(version.manufacturer),
+ version.manufacturer);
+ printf("LMP version:\t%s (0x%x) [subver 0x%x]\n",
+ ver ? ver : "n/a",
+ version.lmp_ver, version.lmp_subver);
+ if (ver)
+ bt_free(ver);
+ }
+
+ if (hci_read_remote_features(dd, handle, features, 20000) == 0) {
+ char *tmp = lmp_featurestostr(features, "\t\t", 63);
+ printf("LMP features:\t0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x"
+ " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ features[0], features[1],
+ features[2], features[3],
+ features[4], features[5],
+ features[6], features[7]);
+ printf("%s\n", tmp);
+ bt_free(tmp);
+ }
+
+ if (cc) {
+ usleep(10000);
+ hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000);
+ }
+ }
+
+ printf("\n");
+ }
+
+ bt_free(info);
+
+ hci_close_dev(dd);
+}
+
+/* Remote name */
+
+static struct option name_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *name_help =
+ "Usage:\n"
+ "\tname <bdaddr>\n";
+
+static void cmd_name(int dev_id, int argc, char **argv)
+{
+ bdaddr_t bdaddr;
+ char name[248];
+ int opt, dd;
+
+ for_each_opt(opt, name_options, NULL) {
+ switch (opt) {
+ default:
+ printf(name_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(name_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_get_route(&bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Device is not available.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ if (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0)
+ printf("%s\n", name);
+
+ hci_close_dev(dd);
+}
+
+/* Info about remote device */
+
+static struct option info_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *info_help =
+ "Usage:\n"
+ "\tinfo <bdaddr>\n";
+
+static void cmd_info(int dev_id, int argc, char **argv)
+{
+ bdaddr_t bdaddr;
+ uint16_t handle;
+ uint8_t max_page, features[8];
+ char name[249], oui[9], *comp;
+ struct hci_version version;
+ struct hci_dev_info di;
+ struct hci_conn_info_req *cr;
+ int opt, dd, cc = 0;
+
+ for_each_opt(opt, info_options, NULL) {
+ switch (opt) {
+ default:
+ printf(info_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(info_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0)
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+
+ if (dev_id < 0)
+ dev_id = hci_get_route(&bdaddr);
+
+ if (dev_id < 0) {
+ fprintf(stderr, "Device is not available or not connected.\n");
+ exit(1);
+ }
+
+ if (hci_devinfo(dev_id, &di) < 0) {
+ perror("Can't get device info");
+ exit(1);
+ }
+
+ printf("Requesting information ...\n");
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't get connection info");
+ close(dd);
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ if (hci_create_connection(dd, &bdaddr,
+ htobs(di.pkt_type & ACL_PTYPE_MASK),
+ 0, 0x01, &handle, 25000) < 0) {
+ perror("Can't create connection");
+ close(dd);
+ exit(1);
+ }
+ cc = 1;
+ } else
+ handle = htobs(cr->conn_info->handle);
+
+ printf("\tBD Address: %s\n", argv[0]);
+
+ ba2oui(&bdaddr, oui);
+ comp = ouitocomp(oui);
+ if (comp) {
+ printf("\tOUI Company: %s (%s)\n", comp, oui);
+ free(comp);
+ }
+
+ if (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0)
+ printf("\tDevice Name: %s\n", name);
+
+ if (hci_read_remote_version(dd, handle, &version, 20000) == 0) {
+ char *ver = lmp_vertostr(version.lmp_ver);
+ printf("\tLMP Version: %s (0x%x) LMP Subversion: 0x%x\n"
+ "\tManufacturer: %s (%d)\n",
+ ver ? ver : "n/a",
+ version.lmp_ver,
+ version.lmp_subver,
+ bt_compidtostr(version.manufacturer),
+ version.manufacturer);
+ if (ver)
+ bt_free(ver);
+ }
+
+ if (hci_read_remote_features(dd, handle, features, 20000) == 0) {
+ char *tmp = lmp_featurestostr(features, "\t\t", 63);
+ printf("\tFeatures: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n%s\n",
+ features[0], features[1], features[2], features[3],
+ features[4], features[5], features[6], features[7], tmp);
+ bt_free(tmp);
+ }
+
+ if ((di.features[7] & LMP_EXT_FEAT) && (features[7] & LMP_EXT_FEAT)) {
+ if (hci_read_remote_ext_features(dd, handle, 0,
+ &max_page, features, 20000) == 0)
+ if (max_page > 0)
+ printf("\tExtended features: %d page%s\n",
+ max_page, max_page > 1 ? "s" : "");
+ }
+
+ if (cc) {
+ usleep(10000);
+ hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000);
+ }
+
+ hci_close_dev(dd);
+}
+
+/* Start periodic inquiry */
+
+static struct option spinq_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *spinq_help =
+ "Usage:\n"
+ "\tspinq\n";
+
+static void cmd_spinq(int dev_id, int argc, char **argv)
+{
+ uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
+ struct hci_request rq;
+ periodic_inquiry_cp cp;
+ int opt, dd;
+
+ for_each_opt(opt, spinq_options, NULL) {
+ switch (opt) {
+ default:
+ printf(spinq_help);
+ return;
+ }
+ }
+
+ if (dev_id < 0)
+ dev_id = hci_get_route(NULL);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("Device open failed");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(cp.lap, lap, 3);
+ cp.max_period = htobs(16);
+ cp.min_period = htobs(10);
+ cp.length = 8;
+ cp.num_rsp = 0;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_PERIODIC_INQUIRY;
+ rq.cparam = &cp;
+ rq.clen = PERIODIC_INQUIRY_CP_SIZE;
+
+ if (hci_send_req(dd, &rq, 100) < 0) {
+ perror("Periodic inquiry failed");
+ exit(EXIT_FAILURE);
+ }
+
+ hci_close_dev(dd);
+}
+
+/* Exit periodic inquiry */
+
+static struct option epinq_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *epinq_help =
+ "Usage:\n"
+ "\tspinq\n";
+
+static void cmd_epinq(int dev_id, int argc, char **argv)
+{
+ int opt, dd;
+
+ for_each_opt(opt, epinq_options, NULL) {
+ switch (opt) {
+ default:
+ printf(epinq_help);
+ return;
+ }
+ }
+
+ if (dev_id < 0)
+ dev_id = hci_get_route(NULL);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("Device open failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if (hci_send_cmd(dd, OGF_LINK_CTL,
+ OCF_EXIT_PERIODIC_INQUIRY, 0, NULL) < 0) {
+ perror("Exit periodic inquiry failed");
+ exit(EXIT_FAILURE);
+ }
+
+ hci_close_dev(dd);
+}
+
+/* Send arbitrary HCI commands */
+
+static struct option cmd_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *cmd_help =
+ "Usage:\n"
+ "\tcmd <ogf> <ocf> [parameters]\n"
+ "Example:\n"
+ "\tcmd 0x03 0x0013 0x41 0x42 0x43 0x44\n";
+
+static void cmd_cmd(int dev_id, int argc, char **argv)
+{
+ unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
+ struct hci_filter flt;
+ hci_event_hdr *hdr;
+ int i, opt, len, dd;
+ uint16_t ocf;
+ uint8_t ogf;
+
+ for_each_opt(opt, cmd_options, NULL) {
+ switch (opt) {
+ default:
+ printf(cmd_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ printf(cmd_help);
+ return;
+ }
+
+ if (dev_id < 0)
+ dev_id = hci_get_route(NULL);
+
+ errno = 0;
+ ogf = strtol(argv[0], NULL, 16);
+ ocf = strtol(argv[1], NULL, 16);
+ if (errno == ERANGE || (ogf > 0x3f) || (ocf > 0x3ff)) {
+ printf(cmd_help);
+ return;
+ }
+
+ for (i = 2, len = 0; i < argc && len < sizeof(buf); i++, len++)
+ *ptr++ = (uint8_t) strtol(argv[i], NULL, 16);
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("Device open failed");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Setup filter */
+ hci_filter_clear(&flt);
+ hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
+ hci_filter_all_events(&flt);
+ if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+ perror("HCI filter setup failed");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("< HCI Command: ogf 0x%02x, ocf 0x%04x, plen %d\n", ogf, ocf, len);
+ hex_dump(" ", 20, buf, len); fflush(stdout);
+
+ if (hci_send_cmd(dd, ogf, ocf, len, buf) < 0) {
+ perror("Send failed");
+ exit(EXIT_FAILURE);
+ }
+
+ len = read(dd, buf, sizeof(buf));
+ if (len < 0) {
+ perror("Read failed");
+ exit(EXIT_FAILURE);
+ }
+
+ hdr = (void *)(buf + 1);
+ ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
+ len -= (1 + HCI_EVENT_HDR_SIZE);
+
+ printf("> HCI Event: 0x%02x plen %d\n", hdr->evt, hdr->plen);
+ hex_dump(" ", 20, ptr, len); fflush(stdout);
+
+ hci_close_dev(dd);
+}
+
+/* Display active connections */
+
+static struct option con_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *con_help =
+ "Usage:\n"
+ "\tcon\n";
+
+static void cmd_con(int dev_id, int argc, char **argv)
+{
+ int opt;
+
+ for_each_opt(opt, con_options, NULL) {
+ switch (opt) {
+ default:
+ printf(con_help);
+ return;
+ }
+ }
+
+ printf("Connections:\n");
+
+ hci_for_each_dev(HCI_UP, conn_list, dev_id);
+}
+
+/* Create connection */
+
+static struct option cc_options[] = {
+ { "help", 0, 0, 'h' },
+ { "role", 1, 0, 'r' },
+ { "ptype", 1, 0, 'p' },
+ { 0, 0, 0, 0 }
+};
+
+static char *cc_help =
+ "Usage:\n"
+ "\tcc [--role=m|s] [--ptype=pkt_types] <bdaddr>\n"
+ "Example:\n"
+ "\tcc --ptype=dm1,dh3,dh5 01:02:03:04:05:06\n"
+ "\tcc --role=m 01:02:03:04:05:06\n";
+
+static void cmd_cc(int dev_id, int argc, char **argv)
+{
+ bdaddr_t bdaddr;
+ uint16_t handle;
+ uint8_t role;
+ unsigned int ptype;
+ int dd, opt;
+
+ role = 0x01;
+ ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;
+
+ for_each_opt(opt, cc_options, NULL) {
+ switch (opt) {
+ case 'p':
+ hci_strtoptype(optarg, &ptype);
+ break;
+
+ case 'r':
+ role = optarg[0] == 'm' ? 0 : 1;
+ break;
+
+ default:
+ printf(cc_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(cc_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_get_route(&bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Device is not available.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ if (hci_create_connection(dd, &bdaddr, htobs(ptype),
+ htobs(0x0000), role, &handle, 25000) < 0)
+ perror("Can't create connection");
+
+ hci_close_dev(dd);
+}
+
+/* Close connection */
+
+static struct option dc_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *dc_help =
+ "Usage:\n"
+ "\tdc <bdaddr>\n";
+
+static void cmd_dc(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ int opt, dd;
+
+ for_each_opt(opt, dc_options, NULL) {
+ switch (opt) {
+ default:
+ printf(dc_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(dc_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (hci_disconnect(dd, htobs(cr->conn_info->handle),
+ HCI_OE_USER_ENDED_CONNECTION, 10000) < 0)
+ perror("Disconnect failed");
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Role switch */
+
+static struct option sr_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *sr_help =
+ "Usage:\n"
+ "\tsr <bdaddr> <role>\n";
+
+static void cmd_sr(int dev_id, int argc, char **argv)
+{
+ bdaddr_t bdaddr;
+ uint8_t role;
+ int opt, dd;
+
+ for_each_opt(opt, sr_options, NULL) {
+ switch (opt) {
+ default:
+ printf(sr_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ printf(sr_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+ switch (argv[1][0]) {
+ case 'm':
+ role = 0;
+ break;
+ case 's':
+ role = 1;
+ break;
+ default:
+ role = atoi(argv[1]);
+ break;
+ }
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ if (hci_switch_role(dd, &bdaddr, role, 10000) < 0) {
+ perror("Switch role request failed");
+ exit(1);
+ }
+
+ hci_close_dev(dd);
+}
+
+/* Read RSSI */
+
+static struct option rssi_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *rssi_help =
+ "Usage:\n"
+ "\trssi <bdaddr>\n";
+
+static void cmd_rssi(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ int8_t rssi;
+ int opt, dd;
+
+ for_each_opt(opt, rssi_options, NULL) {
+ switch (opt) {
+ default:
+ printf(rssi_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(rssi_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (hci_read_rssi(dd, htobs(cr->conn_info->handle), &rssi, 1000) < 0) {
+ perror("Read RSSI failed");
+ exit(1);
+ }
+
+ printf("RSSI return value: %d\n", rssi);
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Get link quality */
+
+static struct option lq_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *lq_help =
+ "Usage:\n"
+ "\tlq <bdaddr>\n";
+
+static void cmd_lq(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint8_t lq;
+ int opt, dd;
+
+ for_each_opt(opt, lq_options, NULL) {
+ switch (opt) {
+ default:
+ printf(lq_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(lq_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (hci_read_link_quality(dd, htobs(cr->conn_info->handle), &lq, 1000) < 0) {
+ perror("HCI read_link_quality request failed");
+ exit(1);
+ }
+
+ printf("Link quality: %d\n", lq);
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Get transmit power level */
+
+static struct option tpl_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *tpl_help =
+ "Usage:\n"
+ "\ttpl <bdaddr> [type]\n";
+
+static void cmd_tpl(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint8_t type;
+ int8_t level;
+ int opt, dd;
+
+ for_each_opt(opt, tpl_options, NULL) {
+ switch (opt) {
+ default:
+ printf(tpl_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(tpl_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+ type = (argc > 1) ? atoi(argv[1]) : 0;
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (hci_read_transmit_power_level(dd, htobs(cr->conn_info->handle), type, &level, 1000) < 0) {
+ perror("HCI read transmit power level request failed");
+ exit(1);
+ }
+
+ printf("%s transmit power level: %d\n",
+ (type == 0) ? "Current" : "Maximum", level);
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Get AFH channel map */
+
+static struct option afh_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *afh_help =
+ "Usage:\n"
+ "\tafh <bdaddr>\n";
+
+static void cmd_afh(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint16_t handle;
+ uint8_t mode, map[10];
+ int opt, dd;
+
+ for_each_opt(opt, afh_options, NULL) {
+ switch (opt) {
+ default:
+ printf(afh_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(afh_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ handle = htobs(cr->conn_info->handle);
+
+ if (hci_read_afh_map(dd, handle, &mode, map, 1000) < 0) {
+ perror("HCI read AFH map request failed");
+ exit(1);
+ }
+
+ if (mode == 0x01) {
+ int i;
+ printf("AFH map: 0x");
+ for (i = 0; i < 10; i++)
+ printf("%02x", map[i]);
+ printf("\n");
+ } else
+ printf("AFH disabled\n");
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Set connection packet type */
+
+static struct option cpt_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *cpt_help =
+ "Usage:\n"
+ "\tcpt <bdaddr> <packet_types>\n";
+
+static void cmd_cpt(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ struct hci_request rq;
+ set_conn_ptype_cp cp;
+ evt_conn_ptype_changed rp;
+ bdaddr_t bdaddr;
+ unsigned int ptype;
+ int dd, opt;
+
+ for_each_opt(opt, cpt_options, NULL) {
+ switch (opt) {
+ default:
+ printf(cpt_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2) {
+ printf(cpt_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+ hci_strtoptype(argv[1], &ptype);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ cp.handle = htobs(cr->conn_info->handle);
+ cp.pkt_type = ptype;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_LINK_CTL;
+ rq.ocf = OCF_SET_CONN_PTYPE;
+ rq.cparam = &cp;
+ rq.clen = SET_CONN_PTYPE_CP_SIZE;
+ rq.rparam = &rp;
+ rq.rlen = EVT_CONN_PTYPE_CHANGED_SIZE;
+ rq.event = EVT_CONN_PTYPE_CHANGED;
+
+ if (hci_send_req(dd, &rq, 100) < 0) {
+ perror("Packet type change failed");
+ exit(1);
+ }
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Get/Set link policy settings */
+
+static struct option lp_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *lp_help =
+ "Usage:\n"
+ "\tlp <bdaddr> [link policy]\n";
+
+static void cmd_lp(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint16_t policy;
+ int opt, dd;
+
+ for_each_opt(opt, lp_options, NULL) {
+ switch (opt) {
+ default:
+ printf(lp_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(lp_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (argc == 1) {
+ char *str;
+ if (hci_read_link_policy(dd, htobs(cr->conn_info->handle),
+ &policy, 1000) < 0) {
+ perror("HCI read_link_policy_settings request failed");
+ exit(1);
+ }
+
+ policy = btohs(policy);
+ str = hci_lptostr(policy);
+ if (str) {
+ printf("Link policy settings: %s\n", str);
+ bt_free(str);
+ } else {
+ fprintf(stderr, "Invalig settings\n");
+ exit(1);
+ }
+ } else {
+ unsigned int val;
+ if (hci_strtolp(argv[1], &val) < 0) {
+ fprintf(stderr, "Invalig arguments\n");
+ exit(1);
+ }
+ policy = val;
+
+ if (hci_write_link_policy(dd, htobs(cr->conn_info->handle),
+ htobs(policy), 1000) < 0) {
+ perror("HCI write_link_policy_settings request failed");
+ exit(1);
+ }
+ }
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Get/Set link supervision timeout */
+
+static struct option lst_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *lst_help =
+ "Usage:\n"
+ "\tlst <bdaddr> [new value in slots]\n";
+
+static void cmd_lst(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint16_t timeout;
+ int opt, dd;
+
+ for_each_opt(opt, lst_options, NULL) {
+ switch (opt) {
+ default:
+ printf(lst_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(lst_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (argc == 1) {
+ if (hci_read_link_supervision_timeout(dd, htobs(cr->conn_info->handle),
+ &timeout, 1000) < 0) {
+ perror("HCI read_link_supervision_timeout request failed");
+ exit(1);
+ }
+
+ timeout = btohs(timeout);
+
+ if (timeout)
+ printf("Link supervision timeout: %u slots (%.2f msec)\n",
+ timeout, (float) timeout * 0.625);
+ else
+ printf("Link supervision timeout never expires\n");
+ } else {
+ timeout = strtol(argv[1], NULL, 10);
+
+ if (hci_write_link_supervision_timeout(dd, htobs(cr->conn_info->handle),
+ htobs(timeout), 1000) < 0) {
+ perror("HCI write_link_supervision_timeout request failed");
+ exit(1);
+ }
+ }
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Request authentication */
+
+static struct option auth_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *auth_help =
+ "Usage:\n"
+ "\tauth <bdaddr>\n";
+
+static void cmd_auth(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ int opt, dd;
+
+ for_each_opt(opt, auth_options, NULL) {
+ switch (opt) {
+ default:
+ printf(auth_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(auth_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000) < 0) {
+ perror("HCI authentication request failed");
+ exit(1);
+ }
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Activate encryption */
+
+static struct option enc_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *enc_help =
+ "Usage:\n"
+ "\tenc <bdaddr> [encrypt enable]\n";
+
+static void cmd_enc(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint8_t encrypt;
+ int opt, dd;
+
+ for_each_opt(opt, enc_options, NULL) {
+ switch (opt) {
+ default:
+ printf(enc_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(enc_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ encrypt = (argc > 1) ? atoi(argv[1]) : 1;
+
+ if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), encrypt, 25000) < 0) {
+ perror("HCI set encryption request failed");
+ exit(1);
+ }
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Change connection link key */
+
+static struct option key_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *key_help =
+ "Usage:\n"
+ "\tkey <bdaddr>\n";
+
+static void cmd_key(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ int opt, dd;
+
+ for_each_opt(opt, key_options, NULL) {
+ switch (opt) {
+ default:
+ printf(key_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(key_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (hci_change_link_key(dd, htobs(cr->conn_info->handle), 25000) < 0) {
+ perror("Changing link key failed");
+ exit(1);
+ }
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Read clock offset */
+
+static struct option clkoff_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *clkoff_help =
+ "Usage:\n"
+ "\tclkoff <bdaddr>\n";
+
+static void cmd_clkoff(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint16_t offset;
+ int opt, dd;
+
+ for_each_opt(opt, clkoff_options, NULL) {
+ switch (opt) {
+ default:
+ printf(clkoff_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(clkoff_help);
+ return;
+ }
+
+ str2ba(argv[0], &bdaddr);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ exit(1);
+ }
+
+ if (hci_read_clock_offset(dd, htobs(cr->conn_info->handle), &offset, 1000) < 0) {
+ perror("Reading clock offset failed");
+ exit(1);
+ }
+
+ printf("Clock offset: 0x%4.4x\n", btohs(offset));
+
+ free(cr);
+
+ hci_close_dev(dd);
+}
+
+/* Read clock */
+
+static struct option clock_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *clock_help =
+ "Usage:\n"
+ "\tclock [bdaddr] [which clock]\n";
+
+static void cmd_clock(int dev_id, int argc, char **argv)
+{
+ struct hci_conn_info_req *cr;
+ bdaddr_t bdaddr;
+ uint8_t which;
+ uint32_t handle, clock;
+ uint16_t accuracy;
+ int opt, dd;
+
+ for_each_opt(opt, clock_options, NULL) {
+ switch (opt) {
+ default:
+ printf(clock_help);
+ return;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ str2ba(argv[0], &bdaddr);
+ else
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ if (dev_id < 0 && !bacmp(&bdaddr, BDADDR_ANY))
+ dev_id = hci_get_route(NULL);
+
+ if (dev_id < 0) {
+ dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
+ if (dev_id < 0) {
+ fprintf(stderr, "Not connected.\n");
+ exit(1);
+ }
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ exit(1);
+ }
+
+ if (bacmp(&bdaddr, BDADDR_ANY)) {
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (!cr) {
+ perror("Can't allocate memory");
+ exit(1);
+ }
+
+ bacpy(&cr->bdaddr, &bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ perror("Get connection info failed");
+ free(cr);
+ exit(1);
+ }
+
+ handle = htobs(cr->conn_info->handle);
+ which = (argc > 1) ? atoi(argv[1]) : 0x01;
+
+ free(cr);
+ } else {
+ handle = 0x00;
+ which = 0x00;
+ }
+
+ if (hci_read_clock(dd, handle, which, &clock, &accuracy, 1000) < 0) {
+ perror("Reading clock failed");
+ exit(1);
+ }
+
+ accuracy = btohs(accuracy);
+
+ printf("Clock: 0x%4.4x\n", btohl(clock));
+ printf("Accuracy: %.2f msec\n", (float) accuracy * 0.3125);
+
+ hci_close_dev(dd);
+}
+
+static struct {
+ char *cmd;
+ void (*func)(int dev_id, int argc, char **argv);
+ char *doc;
+} command[] = {
+ { "dev", cmd_dev, "Display local devices" },
+ { "inq", cmd_inq, "Inquire remote devices" },
+ { "scan", cmd_scan, "Scan for remote devices" },
+ { "name", cmd_name, "Get name from remote device" },
+ { "info", cmd_info, "Get information from remote device" },
+ { "spinq", cmd_spinq, "Start periodic inquiry" },
+ { "epinq", cmd_epinq, "Exit periodic inquiry" },
+ { "cmd", cmd_cmd, "Submit arbitrary HCI commands" },
+ { "con", cmd_con, "Display active connections" },
+ { "cc", cmd_cc, "Create connection to remote device" },
+ { "dc", cmd_dc, "Disconnect from remote device" },
+ { "sr", cmd_sr, "Switch master/slave role" },
+ { "cpt", cmd_cpt, "Change connection packet type" },
+ { "rssi", cmd_rssi, "Display connection RSSI" },
+ { "lq", cmd_lq, "Display link quality" },
+ { "tpl", cmd_tpl, "Display transmit power level" },
+ { "afh", cmd_afh, "Display AFH channel map" },
+ { "lp", cmd_lp, "Set/display link policy settings" },
+ { "lst", cmd_lst, "Set/display link supervision timeout" },
+ { "auth", cmd_auth, "Request authentication" },
+ { "enc", cmd_enc, "Set connection encryption" },
+ { "key", cmd_key, "Change connection link key" },
+ { "clkoff", cmd_clkoff, "Read clock offset" },
+ { "clock", cmd_clock, "Read local or remote clock" },
+ { NULL, NULL, 0 }
+};
+
+static void usage(void)
+{
+ int i;
+
+ printf("hcitool - HCI Tool ver %s\n", VERSION);
+ printf("Usage:\n"
+ "\thcitool [options] <command> [command parameters]\n");
+ printf("Options:\n"
+ "\t--help\tDisplay help\n"
+ "\t-i dev\tHCI device\n");
+ printf("Commands:\n");
+ for (i = 0; command[i].cmd; i++)
+ printf("\t%-4s\t%s\n", command[i].cmd,
+ command[i].doc);
+ printf("\n"
+ "For more information on the usage of each command use:\n"
+ "\thcitool <command> --help\n" );
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device", 1, 0, 'i' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ int opt, i, dev_id = -1;
+ bdaddr_t ba;
+
+ while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'i':
+ dev_id = hci_devid(optarg);
+ if (dev_id < 0) {
+ perror("Invalid device");
+ exit(1);
+ }
+ break;
+
+ case 'h':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(0);
+ }
+
+ if (dev_id != -1 && hci_devba(dev_id, &ba) < 0) {
+ perror("Device is not available");
+ exit(1);
+ }
+
+ for (i = 0; command[i].cmd; i++) {
+ if (strncmp(command[i].cmd, argv[0], 3))
+ continue;
+ command[i].func(dev_id, argc, argv);
+ break;
+ }
+ return 0;
+}
diff --git a/utils/tools/hid2hci.8 b/utils/tools/hid2hci.8
new file mode 100644
index 00000000..6aa9be29
--- /dev/null
+++ b/utils/tools/hid2hci.8
@@ -0,0 +1,45 @@
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.TH HID2HCI 8 "JUNE 6, 2003" "" ""
+
+.SH NAME
+hid2hci \- Bluetooth HID to HCI mode switching utility
+.SH SYNOPSIS
+.BR "hid2hci
+[
+.I options
+]
+.SH DESCRIPTION
+.B hid2hci
+is used to set up switch HID proxy Bluetooth dongle into the HCI
+mode and back.
+.SH OPTIONS
+.TP
+.BI -h
+Gives a list of possible options.
+.TP
+.BI -q
+Don't display any messages.
+.TP
+.BI -0
+Switches the device into HCI mode.
+.TP
+.BI -1
+Switches the device into HID mode.
+.SH AUTHOR
+Written by Marcel Holtmann <marcel@holtmann.org>.
+.br
diff --git a/utils/tools/hid2hci.c b/utils/tools/hid2hci.c
new file mode 100644
index 00000000..eee6da8f
--- /dev/null
+++ b/utils/tools/hid2hci.c
@@ -0,0 +1,390 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+
+#include <usb.h>
+
+#ifdef NEED_USB_GET_BUSSES
+static inline struct usb_bus *usb_get_busses(void)
+{
+ return usb_busses;
+}
+#endif
+
+#ifndef USB_DIR_OUT
+#define USB_DIR_OUT 0x00
+#endif
+
+static char devpath[PATH_MAX + 1] = "/dev";
+
+struct hiddev_devinfo {
+ unsigned int bustype;
+ unsigned int busnum;
+ unsigned int devnum;
+ unsigned int ifnum;
+ short vendor;
+ short product;
+ short version;
+ unsigned num_applications;
+};
+
+struct hiddev_report_info {
+ unsigned report_type;
+ unsigned report_id;
+ unsigned num_fields;
+};
+
+typedef __signed__ int __s32;
+
+struct hiddev_usage_ref {
+ unsigned report_type;
+ unsigned report_id;
+ unsigned field_index;
+ unsigned usage_index;
+ unsigned usage_code;
+ __s32 value;
+};
+
+#define HIDIOCGDEVINFO _IOR('H', 0x03, struct hiddev_devinfo)
+#define HIDIOCINITREPORT _IO('H', 0x05)
+#define HIDIOCSREPORT _IOW('H', 0x08, struct hiddev_report_info)
+#define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref)
+
+#define HID_REPORT_TYPE_OUTPUT 2
+
+#define HCI 0
+#define HID 1
+
+struct device_info;
+
+struct device_id {
+ int mode;
+ uint16_t vendor;
+ uint16_t product;
+ int (*func)(struct device_info *dev);
+};
+
+struct device_info {
+ struct usb_device *dev;
+ struct device_id *id;
+};
+
+static int switch_hidproxy(struct device_info *devinfo)
+{
+ struct usb_dev_handle *udev;
+ int err;
+
+ udev = usb_open(devinfo->dev);
+ if (!udev)
+ return -errno;
+
+ err = usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, devinfo->id->mode, 0, NULL, 0, 10000);
+
+ if (err == 0) {
+ err = -1;
+ errno = EALREADY;
+ } else {
+ if (errno == ETIMEDOUT)
+ err = 0;
+ }
+
+ usb_close(udev);
+
+ return err;
+}
+
+static int send_report(int fd, const char *buf, size_t size)
+{
+ struct hiddev_report_info rinfo;
+ struct hiddev_usage_ref uref;
+ int i, err;
+
+ for (i = 0; i < size; i++) {
+ memset(&uref, 0, sizeof(uref));
+ uref.report_type = HID_REPORT_TYPE_OUTPUT;
+ uref.report_id = 0x10;
+ uref.field_index = 0;
+ uref.usage_index = i;
+ uref.usage_code = 0xff000001;
+ uref.value = buf[i] & 0x000000ff;
+ err = ioctl(fd, HIDIOCSUSAGE, &uref);
+ if (err < 0)
+ return err;
+ }
+
+ memset(&rinfo, 0, sizeof(rinfo));
+ rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
+ rinfo.report_id = 0x10;
+ rinfo.num_fields = 1;
+ err = ioctl(fd, HIDIOCSREPORT, &rinfo);
+
+ return err;
+}
+
+static int switch_logitech(struct device_info *devinfo)
+{
+ char devname[PATH_MAX + 1];
+ int i, fd, err = -1;
+
+ for (i = 0; i < 16; i++) {
+ struct hiddev_devinfo dinfo;
+ char rep1[] = { 0xff, 0x80, 0x80, 0x01, 0x00, 0x00 };
+ char rep2[] = { 0xff, 0x80, 0x00, 0x00, 0x30, 0x00 };
+ char rep3[] = { 0xff, 0x81, 0x80, 0x00, 0x00, 0x00 };
+
+ sprintf(devname, "%s/hiddev%d", devpath, i);
+ fd = open(devname, O_RDWR);
+ if (fd < 0) {
+ sprintf(devname, "%s/usb/hiddev%d", devpath, i);
+ fd = open(devname, O_RDWR);
+ if (fd < 0) {
+ sprintf(devname, "%s/usb/hid/hiddev%d", devpath, i);
+ fd = open(devname, O_RDWR);
+ if (fd < 0)
+ continue;
+ }
+ }
+
+ memset(&dinfo, 0, sizeof(dinfo));
+ err = ioctl(fd, HIDIOCGDEVINFO, &dinfo);
+ if (err < 0 || dinfo.busnum != atoi(devinfo->dev->bus->dirname) ||
+ dinfo.devnum != atoi(devinfo->dev->filename)) {
+ close(fd);
+ continue;
+ }
+
+ err = ioctl(fd, HIDIOCINITREPORT, 0);
+ if (err < 0) {
+ close(fd);
+ break;
+ }
+
+ err = send_report(fd, rep1, sizeof(rep1));
+ if (err < 0) {
+ close(fd);
+ break;
+ }
+
+ err = send_report(fd, rep2, sizeof(rep2));
+ if (err < 0) {
+ close(fd);
+ break;
+ }
+
+ err = send_report(fd, rep3, sizeof(rep3));
+ close(fd);
+ break;
+ }
+
+ return err;
+}
+
+static int switch_dell(struct device_info *devinfo)
+{
+ char report[] = { 0x7f, 0x13, 0x00, 0x00 };
+
+ struct usb_dev_handle *handle;
+ int err;
+
+ handle = usb_open(devinfo->dev);
+ if (handle) {
+ usb_claim_interface(handle, 0);
+ usb_detach_kernel_driver_np(handle, 0);
+ }
+
+ err = usb_control_msg(handle,
+ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x09, 0x7f | (0x03 << 8), 0,
+ report, sizeof(report), 10000);
+
+ if (err == 0) {
+ err = -1;
+ errno = EALREADY;
+ } else {
+ if (errno == ETIMEDOUT)
+ err = 0;
+ }
+
+ usb_close(handle);
+
+ return err;
+}
+
+static struct device_id device_list[] = {
+ { HCI, 0x0a12, 0x1000, switch_hidproxy },
+ { HID, 0x0a12, 0x0001, switch_hidproxy },
+ { HCI, 0x0458, 0x1000, switch_hidproxy },
+ { HID, 0x0458, 0x003f, switch_hidproxy },
+ { HCI, 0x05ac, 0x1000, switch_hidproxy },
+ { HID, 0x05ac, 0x8203, switch_hidproxy },
+ { HID, 0x05ac, 0x8204, switch_hidproxy }, /* Apple Mac mini */
+ { HID, 0x05ac, 0x8207, switch_hidproxy }, /* Apple Power Mac G5 */
+ { HCI, 0x046d, 0xc703, switch_logitech },
+ { HCI, 0x046d, 0xc704, switch_logitech },
+ { HCI, 0x046d, 0xc705, switch_logitech },
+ { HCI, 0x046d, 0xc70a, switch_logitech }, /* Logitech diNovo mouse */
+ { HCI, 0x046d, 0xc70b, switch_logitech }, /* Logitech diNovo Laser keyboard */
+ { HCI, 0x046d, 0xc70c, switch_logitech }, /* Logitech diNovo Laser mouse */
+ { HCI, 0x046d, 0xc70e, switch_logitech }, /* Logitech diNovo keyboard */
+ { HCI, 0x046d, 0xc713, switch_logitech }, /* Logitech diNovo Edge */
+ { HCI, 0x046d, 0xc714, switch_logitech }, /* Logitech diNovo Edge */
+ { HCI, 0x413c, 0x8158, switch_dell }, /* Dell Wireless 370 */
+ { HCI, 0x413c, 0x8154, switch_dell }, /* Dell Wireless 410 */
+ { -1 }
+};
+
+static struct device_id *match_device(int mode, uint16_t vendor, uint16_t product)
+{
+ int i;
+
+ for (i = 0; device_list[i].mode >= 0; i++) {
+ if (mode != device_list[i].mode)
+ continue;
+ if (vendor == device_list[i].vendor &&
+ product == device_list[i].product)
+ return &device_list[i];
+ }
+
+ return NULL;
+}
+
+static int find_devices(int mode, struct device_info *devinfo, size_t size)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ struct device_id *id;
+ int count = 0;
+
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_get_busses(); bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next) {
+ id = match_device(mode, dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ if (!id)
+ continue;
+
+ if (count < size) {
+ devinfo[count].dev = dev;
+ devinfo[count].id = id;
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static void usage(void)
+{
+ printf("hid2hci - Bluetooth HID to HCI mode switching utility\n\n");
+
+ printf("Usage:\n"
+ "\thid2hci [options]\n"
+ "\n");
+
+ printf("Options:\n"
+ "\t-h, --help Display help\n"
+ "\t-q, --quiet Don't display any messages\n"
+ "\t-0, --tohci Switch to HCI mode (default)\n"
+ "\t-1, --tohid Switch to HID mode\n"
+ "\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "quiet", 0, 0, 'q' },
+ { "tohci", 0, 0, '0' },
+ { "tohid", 0, 0, '1' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ struct device_info dev[16];
+ int i, opt, num, quiet = 0, mode = HCI;
+
+ while ((opt = getopt_long(argc, argv, "+01qh", main_options, NULL)) != -1) {
+ switch (opt) {
+ case '0':
+ mode = HCI;
+ break;
+ case '1':
+ mode = HID;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ default:
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ usb_init();
+
+ num = find_devices(mode, dev, sizeof(dev) / sizeof(dev[0]));
+ if (num <= 0) {
+ if (!quiet)
+ fprintf(stderr, "No devices in %s mode found\n",
+ mode ? "HCI" : "HID");
+ exit(1);
+ }
+
+ for (i = 0; i < num; i++) {
+ struct device_id *id = dev[i].id;
+
+ if (!quiet)
+ printf("Switching device %04x:%04x to %s mode ",
+ id->vendor, id->product, mode ? "HID" : "HCI");
+ fflush(stdout);
+
+ if (id->func(&dev[i]) < 0) {
+ if (!quiet)
+ printf("failed (%s)\n", strerror(errno));
+ } else {
+ if (!quiet)
+ printf("was successful\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/utils/tools/l2ping.1 b/utils/tools/l2ping.1
new file mode 100644
index 00000000..8f56fb5e
--- /dev/null
+++ b/utils/tools/l2ping.1
@@ -0,0 +1,67 @@
+.TH L2PING 1 "Jan 22 2002" BlueZ "Linux System Administration"
+.SH NAME
+l2ping \- Send L2CAP echo request and receive answer
+.SH SYNOPSIS
+.B l2ping
+.RB [\| \-i
+.IR <hciX> \|]
+.RB [\| \-s
+.IR size \|]
+.RB [\| \-c
+.IR count \|]
+.RB [\| \-t
+.IR timeout \|]
+.RB [\| \-f \|]
+.RB [\| \-r \|]
+.I bd_addr
+
+.SH DESCRIPTION
+.LP
+.I bd_addr
+
+.SH DESCRIPTION
+.LP
+L2ping sends a L2CAP echo request to the Bluetooth MAC address
+.I bd_addr
+given in dotted hex notation.
+.SH OPTIONS
+.TP
+.BI \-i " <hciX>"
+The command is applied to device
+.BI
+hciX
+, which must be the name of an installed Bluetooth device (X = 0, 1, 2, ...)
+If not specified, the command will be sent to the first available Bluetooth
+device.
+.TP
+.BI \-s " size"
+The
+.I size
+of the data packets to be sent.
+.TP
+.BI \-c " count"
+Send
+.I count
+number of packets then exit.
+.TP
+.BI \-t " timeout"
+Wait
+.I timeout
+seconds for the response.
+.TP
+.B \-f
+Kind of flood ping. Use with care! It reduces the delay time between packets
+to 0.
+.TP
+.B \-r
+Reverse ping (gnip?). Send echo response instead of echo request.
+.TP
+.I bd_addr
+The Bluetooth MAC address to be pinged in dotted hex notation like
+.B 01:02:03:ab:cd:ef
+or
+.B 01:EF:cd:aB:02:03
+.SH AUTHORS
+Written by Maxim Krasnyansky <maxk@qualcomm.com> and Marcel Holtmann <marcel@holtmann.org>
+.PP
+man page by Nils Faerber <nils@kernelconcepts.de>, Adam Laurie <adam@algroup.co.uk>.
diff --git a/utils/tools/l2ping.c b/utils/tools/l2ping.c
new file mode 100644
index 00000000..1e2aab6d
--- /dev/null
+++ b/utils/tools/l2ping.c
@@ -0,0 +1,290 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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 <getopt.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+
+/* Defaults */
+static bdaddr_t bdaddr;
+static int size = 44;
+static int ident = 200;
+static int delay = 1;
+static int count = -1;
+static int timeout = 10;
+static int reverse = 0;
+
+/* Stats */
+static int sent_pkt = 0;
+static int recv_pkt = 0;
+
+static float tv2fl(struct timeval tv)
+{
+ return (float)(tv.tv_sec*1000.0) + (float)(tv.tv_usec/1000.0);
+}
+
+static void stat(int sig)
+{
+ int loss = sent_pkt ? (float)((sent_pkt-recv_pkt)/(sent_pkt/100.0)) : 0;
+ printf("%d sent, %d received, %d%% loss\n", sent_pkt, recv_pkt, loss);
+ exit(0);
+}
+
+static void ping(char *svr)
+{
+ struct sigaction sa;
+ struct sockaddr_l2 addr;
+ socklen_t optlen;
+ unsigned char *buf;
+ char str[18];
+ int i, sk, lost;
+ uint8_t id;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = stat;
+ sigaction(SIGINT, &sa, NULL);
+
+ buf = malloc(L2CAP_CMD_HDR_SIZE + size);
+ if (!buf) {
+ perror("Can't allocate buffer");
+ exit(1);
+ }
+
+ /* Create socket */
+ sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (sk < 0) {
+ perror("Can't create socket");
+ free(buf);
+ exit(1);
+ }
+
+ /* Bind to local address */
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, &bdaddr);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Can't bind socket");
+ close(sk);
+ free(buf);
+ exit(1);
+ }
+
+ /* Connect to remote device */
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba(svr, &addr.l2_bdaddr);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Can't connect");
+ close(sk);
+ free(buf);
+ exit(1);
+ }
+
+ /* Get local address */
+ memset(&addr, 0, sizeof(addr));
+ optlen = sizeof(addr);
+
+ if (getsockname(sk, (struct sockaddr *) &addr, &optlen) < 0) {
+ perror("Can't get local address");
+ close(sk);
+ free(buf);
+ exit(1);
+ }
+
+ ba2str(&addr.l2_bdaddr, str);
+ printf("Ping: %s from %s (data size %d) ...\n", svr, str, size);
+
+ /* Initialize buffer */
+ for (i = 0; i < size; i++)
+ buf[L2CAP_CMD_HDR_SIZE + i] = (i % 40) + 'A';
+
+ id = ident;
+
+ while (count == -1 || count-- > 0) {
+ struct timeval tv_send, tv_recv, tv_diff;
+ l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
+
+ /* Build command header */
+ cmd->ident = id;
+ cmd->len = htobs(size);
+
+ if (reverse)
+ cmd->code = L2CAP_ECHO_RSP;
+ else
+ cmd->code = L2CAP_ECHO_REQ;
+
+ gettimeofday(&tv_send, NULL);
+
+ /* Send Echo Command */
+ if (send(sk, buf, L2CAP_CMD_HDR_SIZE + size, 0) <= 0) {
+ perror("Send failed");
+ exit(1);
+ }
+
+ /* Wait for Echo Response */
+ lost = 0;
+ while (1) {
+ struct pollfd pf[1];
+ int err;
+
+ pf[0].fd = sk;
+ pf[0].events = POLLIN;
+
+ if ((err = poll(pf, 1, timeout * 1000)) < 0) {
+ perror("Poll failed");
+ exit(1);
+ }
+
+ if (!err) {
+ lost = 1;
+ break;
+ }
+
+ if ((err = recv(sk, buf, L2CAP_CMD_HDR_SIZE + size, 0)) < 0) {
+ perror("Recv failed");
+ exit(1);
+ }
+
+ if (!err){
+ printf("Disconnected\n");
+ exit(1);
+ }
+
+ cmd->len = btohs(cmd->len);
+
+ /* Check for our id */
+ if (cmd->ident != id)
+ continue;
+
+ /* Check type */
+ if (!reverse && cmd->code == L2CAP_ECHO_RSP)
+ break;
+
+ if (cmd->code == L2CAP_COMMAND_REJ) {
+ printf("Peer doesn't support Echo packets\n");
+ exit(1);
+ }
+
+ }
+ sent_pkt++;
+
+ if (!lost) {
+ recv_pkt++;
+
+ gettimeofday(&tv_recv, NULL);
+ timersub(&tv_recv, &tv_send, &tv_diff);
+
+ printf("%d bytes from %s id %d time %.2fms\n", cmd->len, svr, id - ident, tv2fl(tv_diff));
+
+ if (delay)
+ sleep(delay);
+ } else {
+ printf("no response from %s: id %d\n", svr, id - ident);
+ }
+
+ if (++id > 254)
+ id = ident;
+ }
+ stat(0);
+}
+
+static void usage(void)
+{
+ printf("l2ping - L2CAP ping\n");
+ printf("Usage:\n");
+ printf("\tl2ping [-i device] [-s size] [-c count] [-t timeout] [-f] [-r] <bdaddr>\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+
+ /* Default options */
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ while ((opt=getopt(argc,argv,"i:s:c:t:fr")) != EOF) {
+ switch(opt) {
+ case 'i':
+ if (!strncasecmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &bdaddr);
+ else
+ str2ba(optarg, &bdaddr);
+ break;
+
+ case 'f':
+ /* Kinda flood ping */
+ delay = 0;
+ break;
+
+ case 'r':
+ /* Use responses instead of requests */
+ reverse = 1;
+ break;
+
+ case 'c':
+ count = atoi(optarg);
+ break;
+
+ case 't':
+ timeout = atoi(optarg);
+ break;
+
+ case 's':
+ size = atoi(optarg);
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (!(argc - optind)) {
+ usage();
+ exit(1);
+ }
+
+ ping(argv[optind]);
+
+ return 0;
+}
diff --git a/utils/tools/ppporc.c b/utils/tools/ppporc.c
new file mode 100644
index 00000000..2d8b034d
--- /dev/null
+++ b/utils/tools/ppporc.c
@@ -0,0 +1,273 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <syslog.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+extern int optind, opterr, optopt;
+extern char *optarg;
+
+/* IO cancelation */
+static volatile sig_atomic_t __io_canceled;
+
+static inline void io_init(void)
+{
+ __io_canceled = 0;
+}
+
+static inline void io_cancel(void)
+{
+ __io_canceled = 1;
+}
+
+/* Signal functions */
+static void sig_hup(int sig)
+{
+ return;
+}
+
+static void sig_term(int sig)
+{
+ syslog(LOG_INFO, "Closing RFCOMM channel");
+ io_cancel();
+}
+
+/* Read exactly len bytes (Signal safe)*/
+static inline int read_n(int fd, char *buf, int len)
+{
+ register int t = 0, w;
+
+ while (!__io_canceled && len > 0) {
+ if ((w = read(fd, buf, len)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ if (!w)
+ return 0;
+ len -= w;
+ buf += w;
+ t += w;
+ }
+
+ return t;
+}
+
+/* Write exactly len bytes (Signal safe)*/
+static inline int write_n(int fd, char *buf, int len)
+{
+ register int t = 0, w;
+
+ while (!__io_canceled && len > 0) {
+ if ((w = write(fd, buf, len)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ if (!w)
+ return 0;
+ len -= w;
+ buf += w;
+ t += w;
+ }
+
+ return t;
+}
+
+/* Create the RFCOMM connection */
+static int create_connection(bdaddr_t *bdaddr, uint8_t channel)
+{
+ struct sockaddr_rc remote_addr, local_addr;
+ int fd, err;
+
+ if ((fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0)
+ return fd;
+
+ memset(&local_addr, 0, sizeof(local_addr));
+ local_addr.rc_family = AF_BLUETOOTH;
+ bacpy(&local_addr.rc_bdaddr, BDADDR_ANY);
+ if ((err = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr))) < 0) {
+ close(fd);
+ return err;
+ }
+
+ memset(&remote_addr, 0, sizeof(remote_addr));
+ remote_addr.rc_family = AF_BLUETOOTH;
+ bacpy(&remote_addr.rc_bdaddr, bdaddr);
+ remote_addr.rc_channel = channel;
+ if ((err = connect(fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr))) < 0) {
+ close(fd);
+ return err;
+ }
+
+ syslog(LOG_INFO, "RFCOMM channel %d connected", channel);
+
+ return fd;
+}
+
+/* Process the data from socket and pseudo tty */
+static int process_data(int fd)
+{
+ struct pollfd p[2];
+ char buf[1024];
+ int err, r;
+
+ p[0].fd = 0;
+ p[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
+
+ p[1].fd = fd;
+ p[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
+
+ err = 0;
+
+ while (!__io_canceled) {
+ p[0].revents = 0;
+ p[1].revents = 0;
+
+ err = poll(p, 2, -1);
+ if (err < 0)
+ break;
+
+ err = 0;
+
+ if (p[0].revents) {
+ if (p[0].revents & (POLLERR | POLLHUP | POLLNVAL))
+ break;
+ r = read(0, buf, sizeof(buf));
+ if (r < 0) {
+ if (errno != EINTR && errno != EAGAIN) {
+ err = r;
+ break;
+ }
+ }
+
+ err = write_n(fd, buf, r);
+ if (err < 0)
+ break;
+ }
+
+ if (p[1].revents) {
+ if (p[1].revents & (POLLERR | POLLHUP | POLLNVAL))
+ break;
+ r = read(fd, buf, sizeof(buf));
+ if (r < 0) {
+ if (errno != EINTR && errno != EAGAIN) {
+ err = r;
+ break;
+ }
+ }
+
+ err = write_n(1, buf, r);
+ if (err < 0)
+ break;
+ }
+ }
+
+ return err;
+}
+
+static void usage(void)
+{
+ printf("Usage:\tppporc <bdaddr> [channel]\n");
+}
+
+int main(int argc, char** argv)
+{
+ struct sigaction sa;
+ int fd, err, opt;
+
+ bdaddr_t bdaddr;
+ uint8_t channel;
+
+ /* Parse command line options */
+ while ((opt = getopt(argc, argv, "h")) != EOF) {
+ switch(opt) {
+ case 'h':
+ usage();
+ exit(0);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) {
+ case 1:
+ str2ba(argv[0], &bdaddr);
+ channel = 1;
+ break;
+ case 2:
+ str2ba(argv[0], &bdaddr);
+ channel = atoi(argv[1]);
+ break;
+ default:
+ usage();
+ exit(0);
+ }
+
+ /* Initialize syslog */
+ openlog("ppporc", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
+ syslog(LOG_INFO, "PPP over RFCOMM");
+
+ /* Initialize signals */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_NOCLDSTOP;
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGCHLD, &sa, NULL);
+ sigaction(SIGPIPE, &sa, NULL);
+
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ sa.sa_handler = sig_hup;
+ sigaction(SIGHUP, &sa, NULL);
+
+ syslog(LOG_INFO, "Connecting to %s", argv[0]);
+
+ if ((fd = create_connection(&bdaddr, channel)) < 0) {
+ syslog(LOG_ERR, "Can't connect to remote device (%s)", strerror(errno));
+ return fd;
+ }
+
+ err = process_data(fd);
+
+ close(fd);
+
+ return err;
+}
diff --git a/utils/tools/sdptool.1 b/utils/tools/sdptool.1
new file mode 100644
index 00000000..57b2567f
--- /dev/null
+++ b/utils/tools/sdptool.1
@@ -0,0 +1,130 @@
+.\" $Header: /cvsroot/bluez/utils/tools/sdptool.1,v 1.8 2006/11/23 05:01:13 holtmann Exp $
+.\"
+.\" transcript compatibility for postscript use.
+.\"
+.\" synopsis: .P! <file.ps>
+.\"
+.de P!
+.fl
+\!!1 setgray
+.fl
+\\&.\"
+.fl
+\!!0 setgray
+.fl \" force out current output buffer
+\!!save /psv exch def currentpoint translate 0 0 moveto
+\!!/showpage{}def
+.fl \" prolog
+.sy sed -e 's/^/!/' \\$1\" bring in postscript file
+\!!psv restore
+.
+.de pF
+.ie \\*(f1 .ds f1 \\n(.f
+.el .ie \\*(f2 .ds f2 \\n(.f
+.el .ie \\*(f3 .ds f3 \\n(.f
+.el .ie \\*(f4 .ds f4 \\n(.f
+.el .tm ? font overflow
+.ft \\$1
+..
+.de fP
+.ie !\\*(f4 \{\
+. ft \\*(f4
+. ds f4\"
+' br \}
+.el .ie !\\*(f3 \{\
+. ft \\*(f3
+. ds f3\"
+' br \}
+.el .ie !\\*(f2 \{\
+. ft \\*(f2
+. ds f2\"
+' br \}
+.el .ie !\\*(f1 \{\
+. ft \\*(f1
+. ds f1\"
+' br \}
+.el .tm ? font underflow
+..
+.ds f1\"
+.ds f2\"
+.ds f3\"
+.ds f4\"
+'\" t
+.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
+.TH "sdptool" "1"
+.SH "NAME"
+sdptool \(em control and interrogate SDP servers
+.SH "SYNOPSIS"
+.PP
+\fBsdptool\fR [\fIoptions\fR] {\fIcommand\fR} [\fIcommand parameters\fR \&...]
+.SH "DESCRIPTION"
+.PP
+\fBsdptool\fR provides the interface for
+performing SDP queries on Bluetooth devices, and administering a
+local \fBsdpd\fR.
+.SH "COMMANDS"
+.PP
+The following commands are available. In all cases \fBbdaddr\fR
+specifies the device to search or browse. If \fIlocal\fP is used
+for \fBbdaddr\fP, then the local \fBsdpd\fR is searched.
+.PP
+Services are identified and manipulated with a 4-byte \fBrecord_handle\fP
+(NOT the service name). To find a service's \fBrecord_handle\fP, look for the
+"Service RecHandle" line in the \fBsearch\fP or \fBbrowse\fP results
+.IP "\fBsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] service_name\fP" 10
+Search for services..
+.IP "" 10
+Known service names are DID, SP, DUN, LAN, FAX, OPUSH,
+FTP, HS, HF, HFAG, SAP, NAP, GN, PANU, HCRP, HID, CIP,
+A2SRC, A2SNK, AVRCT, AVRTG, UDIUE, UDITE and SYNCML.
+.IP "\fBbrowse [--tree] [--raw] [--xml] [bdaddr]\fP" 10
+Browse all available services on the device
+specified by a Bluetooth address as a parameter.
+.IP "\fBrecords [--tree] [--raw] [--xml] bdaddr\fP" 10
+Retrieve all possible service records.
+.IP "\fBadd [ --handle=N --channel=N ]\fP" 10
+Add a service to the local
+\fBsdpd\fR.
+.IP "" 10
+You can specify a handle for this record using
+the \fB--handle\fP option.
+.IP "" 10
+You can specify a channel to add the service on
+using the \fB--channel\fP option.
+.IP "\fBdel record_handle\fP" 10
+Remove a service from the local
+\fBsdpd\fR.
+.IP "\fBget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\fP" 10
+Retrieve a service from the local
+\fBsdpd\fR.
+.IP "\fBsetattr record_handle attrib_id attrib_value\fP" 10
+Set or add an attribute to an SDP record.
+
+.IP "\fBsetseq record_handle attrib_id attrib_values\fP" 10
+Set or add an attribute sequence to an
+SDP record.
+.SH "OPTIONS"
+.IP "\fB--help\fP" 10
+Displays help on using sdptool.
+
+.SH "EXAMPLES"
+.PP
+sdptool browse 00:80:98:24:15:6D
+.PP
+sdptool browse local
+.PP
+sdptool add DUN
+.PP
+sdptool del 0x10000
+.SH "BUGS"
+.PP
+Documentation needs improving.
+.SH "AUTHOR"
+.PP
+Maxim Krasnyansky <maxk@qualcomm.com>. Man page written
+by Edd Dumbill <ejad@debian.org>.
+
+.SH "SEE ALSO"
+.PP
+sdpd(8)
+.\" created by instant / docbook-to-man, Thu 15 Jan 2004, 21:01
diff --git a/utils/tools/sdptool.c b/utils/tools/sdptool.c
new file mode 100644
index 00000000..19882396
--- /dev/null
+++ b/utils/tools/sdptool.c
@@ -0,0 +1,4055 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2001-2002 Nokia Corporation
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2008 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>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <netinet/in.h>
+
+#include "sdp-xml.h"
+
+#ifndef APPLE_AGENT_SVCLASS_ID
+#define APPLE_AGENT_SVCLASS_ID 0x2112
+#endif
+
+#define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, 0)) != -1)
+
+/*
+ * Convert a string to a BDADDR, with a few "enhancements" - Jean II
+ */
+static int estr2ba(char *str, bdaddr_t *ba)
+{
+ /* Only trap "local", "any" is already dealt with */
+ if(!strcmp(str, "local")) {
+ bacpy(ba, BDADDR_LOCAL);
+ return 0;
+ }
+ return str2ba(str, ba);
+}
+
+#define DEFAULT_VIEW 0 /* Display only known attribute */
+#define TREE_VIEW 1 /* Display full attribute tree */
+#define RAW_VIEW 2 /* Display raw tree */
+#define XML_VIEW 3 /* Display xml tree */
+
+/* Pass args to the inquiry/search handler */
+struct search_context {
+ char *svc; /* Service */
+ uuid_t group; /* Browse group */
+ int view; /* View mode */
+ uint32_t handle; /* Service record handle */
+};
+
+typedef int (*handler_t)(bdaddr_t *bdaddr, struct search_context *arg);
+
+static char UUID_str[MAX_LEN_UUID_STR];
+static bdaddr_t interface;
+
+/* Definition of attribute members */
+struct member_def {
+ char *name;
+};
+
+/* Definition of an attribute */
+struct attrib_def {
+ int num; /* Numeric ID - 16 bits */
+ char *name; /* User readable name */
+ struct member_def *members; /* Definition of attribute args */
+ int member_max; /* Max of attribute arg definitions */
+};
+
+/* Definition of a service or protocol */
+struct uuid_def {
+ int num; /* Numeric ID - 16 bits */
+ char *name; /* User readable name */
+ struct attrib_def *attribs; /* Specific attribute definitions */
+ int attrib_max; /* Max of attribute definitions */
+};
+
+/* Context information about current attribute */
+struct attrib_context {
+ struct uuid_def *service; /* Service UUID, if known */
+ struct attrib_def *attrib; /* Description of the attribute */
+ int member_index; /* Index of current attribute member */
+};
+
+/* Context information about the whole service */
+struct service_context {
+ struct uuid_def *service; /* Service UUID, if known */
+};
+
+/* Allow us to do nice formatting of the lists */
+static char *indent_spaces = " ";
+
+/* ID of the service attribute.
+ * Most attributes after 0x200 are defined based on the service, so
+ * we need to find what is the service (which is messy) - Jean II */
+#define SERVICE_ATTR 0x1
+
+/* Definition of the optional arguments in protocol list */
+static struct member_def protocol_members[] = {
+ { "Protocol" },
+ { "Channel/Port" },
+ { "Version" },
+};
+
+/* Definition of the optional arguments in profile list */
+static struct member_def profile_members[] = {
+ { "Profile" },
+ { "Version" },
+};
+
+/* Definition of the optional arguments in Language list */
+static struct member_def language_members[] = {
+ { "Code ISO639" },
+ { "Encoding" },
+ { "Base Offset" },
+};
+
+/* Name of the various common attributes. See BT assigned numbers */
+static struct attrib_def attrib_names[] = {
+ { 0x0, "ServiceRecordHandle", NULL, 0 },
+ { 0x1, "ServiceClassIDList", NULL, 0 },
+ { 0x2, "ServiceRecordState", NULL, 0 },
+ { 0x3, "ServiceID", NULL, 0 },
+ { 0x4, "ProtocolDescriptorList",
+ protocol_members, sizeof(protocol_members)/sizeof(struct member_def) },
+ { 0x5, "BrowseGroupList", NULL, 0 },
+ { 0x6, "LanguageBaseAttributeIDList",
+ language_members, sizeof(language_members)/sizeof(struct member_def) },
+ { 0x7, "ServiceInfoTimeToLive", NULL, 0 },
+ { 0x8, "ServiceAvailability", NULL, 0 },
+ { 0x9, "BluetoothProfileDescriptorList",
+ profile_members, sizeof(profile_members)/sizeof(struct member_def) },
+ { 0xA, "DocumentationURL", NULL, 0 },
+ { 0xB, "ClientExecutableURL", NULL, 0 },
+ { 0xC, "IconURL", NULL, 0 },
+ { 0xD, "AdditionalProtocolDescriptorLists", NULL, 0 },
+ /* Definitions after that are tricky (per profile or offset) */
+};
+
+const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);
+
+/* Name of the various SPD attributes. See BT assigned numbers */
+static struct attrib_def sdp_attrib_names[] = {
+ { 0x200, "VersionNumberList", NULL, 0 },
+ { 0x201, "ServiceDatabaseState", NULL, 0 },
+};
+
+/* Name of the various SPD attributes. See BT assigned numbers */
+static struct attrib_def browse_attrib_names[] = {
+ { 0x200, "GroupID", NULL, 0 },
+};
+
+/* Name of the various Device ID attributes. See Device Id spec. */
+static struct attrib_def did_attrib_names[] = {
+ { 0x200, "SpecificationID", NULL, 0 },
+ { 0x201, "VendorID", NULL, 0 },
+ { 0x202, "ProductID", NULL, 0 },
+ { 0x203, "Version", NULL, 0 },
+ { 0x204, "PrimaryRecord", NULL, 0 },
+ { 0x205, "VendorIDSource", NULL, 0 },
+};
+
+/* Name of the various HID attributes. See HID spec. */
+static struct attrib_def hid_attrib_names[] = {
+ { 0x200, "DeviceReleaseNum", NULL, 0 },
+ { 0x201, "ParserVersion", NULL, 0 },
+ { 0x202, "DeviceSubclass", NULL, 0 },
+ { 0x203, "CountryCode", NULL, 0 },
+ { 0x204, "VirtualCable", NULL, 0 },
+ { 0x205, "ReconnectInitiate", NULL, 0 },
+ { 0x206, "DescriptorList", NULL, 0 },
+ { 0x207, "LangIDBaseList", NULL, 0 },
+ { 0x208, "SDPDisable", NULL, 0 },
+ { 0x209, "BatteryPower", NULL, 0 },
+ { 0x20a, "RemoteWakeup", NULL, 0 },
+ { 0x20b, "ProfileVersion", NULL, 0 },
+ { 0x20c, "SupervisionTimeout", NULL, 0 },
+ { 0x20d, "NormallyConnectable", NULL, 0 },
+ { 0x20e, "BootDevice", NULL, 0 },
+};
+
+/* Name of the various PAN attributes. See BT assigned numbers */
+/* Note : those need to be double checked - Jean II */
+static struct attrib_def pan_attrib_names[] = {
+ { 0x200, "IpSubnet", NULL, 0 }, /* Obsolete ??? */
+ { 0x30A, "SecurityDescription", NULL, 0 },
+ { 0x30B, "NetAccessType", NULL, 0 },
+ { 0x30C, "MaxNetAccessrate", NULL, 0 },
+ { 0x30D, "IPv4Subnet", NULL, 0 },
+ { 0x30E, "IPv6Subnet", NULL, 0 },
+};
+
+/* Name of the various Generic-Audio attributes. See BT assigned numbers */
+/* Note : totally untested - Jean II */
+static struct attrib_def audio_attrib_names[] = {
+ { 0x302, "Remote audio volume control", NULL, 0 },
+};
+
+/* Same for the UUIDs. See BT assigned numbers */
+static struct uuid_def uuid16_names[] = {
+ /* -- Protocols -- */
+ { 0x0001, "SDP", NULL, 0 },
+ { 0x0002, "UDP", NULL, 0 },
+ { 0x0003, "RFCOMM", NULL, 0 },
+ { 0x0004, "TCP", NULL, 0 },
+ { 0x0005, "TCS-BIN", NULL, 0 },
+ { 0x0006, "TCS-AT", NULL, 0 },
+ { 0x0008, "OBEX", NULL, 0 },
+ { 0x0009, "IP", NULL, 0 },
+ { 0x000a, "FTP", NULL, 0 },
+ { 0x000c, "HTTP", NULL, 0 },
+ { 0x000e, "WSP", NULL, 0 },
+ { 0x000f, "BNEP", NULL, 0 },
+ { 0x0010, "UPnP/ESDP", NULL, 0 },
+ { 0x0011, "HIDP", NULL, 0 },
+ { 0x0012, "HardcopyControlChannel", NULL, 0 },
+ { 0x0014, "HardcopyDataChannel", NULL, 0 },
+ { 0x0016, "HardcopyNotification", NULL, 0 },
+ { 0x0017, "AVCTP", NULL, 0 },
+ { 0x0019, "AVDTP", NULL, 0 },
+ { 0x001b, "CMTP", NULL, 0 },
+ { 0x001d, "UDI_C-Plane", NULL, 0 },
+ { 0x0100, "L2CAP", NULL, 0 },
+ /* -- Services -- */
+ { 0x1000, "ServiceDiscoveryServerServiceClassID",
+ sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1001, "BrowseGroupDescriptorServiceClassID",
+ browse_attrib_names, sizeof(browse_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1002, "PublicBrowseGroup", NULL, 0 },
+ { 0x1101, "SerialPort", NULL, 0 },
+ { 0x1102, "LANAccessUsingPPP", NULL, 0 },
+ { 0x1103, "DialupNetworking (DUN)", NULL, 0 },
+ { 0x1104, "IrMCSync", NULL, 0 },
+ { 0x1105, "OBEXObjectPush", NULL, 0 },
+ { 0x1106, "OBEXFileTransfer", NULL, 0 },
+ { 0x1107, "IrMCSyncCommand", NULL, 0 },
+ { 0x1108, "Headset",
+ audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1109, "CordlessTelephony", NULL, 0 },
+ { 0x110a, "AudioSource", NULL, 0 },
+ { 0x110b, "AudioSink", NULL, 0 },
+ { 0x110c, "RemoteControlTarget", NULL, 0 },
+ { 0x110d, "AdvancedAudio", NULL, 0 },
+ { 0x110e, "RemoteControl", NULL, 0 },
+ { 0x110f, "VideoConferencing", NULL, 0 },
+ { 0x1110, "Intercom", NULL, 0 },
+ { 0x1111, "Fax", NULL, 0 },
+ { 0x1112, "HeadsetAudioGateway", NULL, 0 },
+ { 0x1113, "WAP", NULL, 0 },
+ { 0x1114, "WAP Client", NULL, 0 },
+ { 0x1115, "PANU (PAN/BNEP)",
+ pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1116, "NAP (PAN/BNEP)",
+ pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1117, "GN (PAN/BNEP)",
+ pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1118, "DirectPrinting (BPP)", NULL, 0 },
+ { 0x1119, "ReferencePrinting (BPP)", NULL, 0 },
+ { 0x111a, "Imaging (BIP)", NULL, 0 },
+ { 0x111b, "ImagingResponder (BIP)", NULL, 0 },
+ { 0x111c, "ImagingAutomaticArchive (BIP)", NULL, 0 },
+ { 0x111d, "ImagingReferencedObjects (BIP)", NULL, 0 },
+ { 0x111e, "Handsfree", NULL, 0 },
+ { 0x111f, "HandsfreeAudioGateway", NULL, 0 },
+ { 0x1120, "DirectPrintingReferenceObjectsService (BPP)", NULL, 0 },
+ { 0x1121, "ReflectedUI (BPP)", NULL, 0 },
+ { 0x1122, "BasicPrinting (BPP)", NULL, 0 },
+ { 0x1123, "PrintingStatus (BPP)", NULL, 0 },
+ { 0x1124, "HumanInterfaceDeviceService (HID)",
+ hid_attrib_names, sizeof(hid_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1125, "HardcopyCableReplacement (HCR)", NULL, 0 },
+ { 0x1126, "HCR_Print (HCR)", NULL, 0 },
+ { 0x1127, "HCR_Scan (HCR)", NULL, 0 },
+ { 0x1128, "Common ISDN Access (CIP)", NULL, 0 },
+ { 0x1129, "VideoConferencingGW (VCP)", NULL, 0 },
+ { 0x112a, "UDI-MT", NULL, 0 },
+ { 0x112b, "UDI-TA", NULL, 0 },
+ { 0x112c, "Audio/Video", NULL, 0 },
+ { 0x112d, "SIM Access (SAP)", NULL, 0 },
+ { 0x112e, "Phonebook Access (PBAP) - PCE", NULL, 0 },
+ { 0x112f, "Phonebook Access (PBAP) - PSE", NULL, 0 },
+ { 0x1130, "Phonebook Access (PBAP)", NULL, 0 },
+ /* ... */
+ { 0x1200, "PnPInformation",
+ did_attrib_names, sizeof(did_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1201, "GenericNetworking", NULL, 0 },
+ { 0x1202, "GenericFileTransfer", NULL, 0 },
+ { 0x1203, "GenericAudio",
+ audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
+ { 0x1204, "GenericTelephony", NULL, 0 },
+ /* ... */
+ { 0x1303, "VideoSource", NULL, 0 },
+ { 0x1304, "VideoSink", NULL, 0 },
+ { 0x1305, "VideoDistribution", NULL, 0 },
+ { 0x1400, "MDP", NULL, 0 },
+ { 0x1401, "MDPSource", NULL, 0 },
+ { 0x1402, "MDPSink", NULL, 0 },
+ { 0x2112, "AppleAgent", NULL, 0 },
+};
+
+static const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);
+
+static void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);
+
+/*
+ * Parse a UUID.
+ * The BT assigned numbers only list UUID16, so I'm not sure the
+ * other types will ever get used...
+ */
+static void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent)
+{
+ if (uuid) {
+ if (uuid->type == SDP_UUID16) {
+ uint16_t uuidNum = uuid->value.uuid16;
+ struct uuid_def *uuidDef = NULL;
+ int i;
+
+ for (i = 0; i < uuid16_max; i++)
+ if (uuid16_names[i].num == uuidNum) {
+ uuidDef = &uuid16_names[i];
+ break;
+ }
+
+ /* Check if it's the service attribute */
+ if (context->attrib && context->attrib->num == SERVICE_ATTR) {
+ /* We got the service ID !!! */
+ context->service = uuidDef;
+ }
+
+ if (uuidDef)
+ printf("%.*sUUID16 : 0x%.4x - %s\n",
+ indent, indent_spaces, uuidNum, uuidDef->name);
+ else
+ printf("%.*sUUID16 : 0x%.4x\n",
+ indent, indent_spaces, uuidNum);
+ } else if (uuid->type == SDP_UUID32) {
+ struct uuid_def *uuidDef = NULL;
+ int i;
+
+ if (!(uuid->value.uuid32 & 0xffff0000)) {
+ uint16_t uuidNum = uuid->value.uuid32;
+ for (i = 0; i < uuid16_max; i++)
+ if (uuid16_names[i].num == uuidNum) {
+ uuidDef = &uuid16_names[i];
+ break;
+ }
+ }
+
+ if (uuidDef)
+ printf("%.*sUUID32 : 0x%.8x - %s\n",
+ indent, indent_spaces, uuid->value.uuid32, uuidDef->name);
+ else
+ printf("%.*sUUID32 : 0x%.8x\n",
+ indent, indent_spaces, uuid->value.uuid32);
+ } else if (uuid->type == SDP_UUID128) {
+ unsigned int data0;
+ unsigned short data1;
+ unsigned short data2;
+ unsigned short data3;
+ unsigned int data4;
+ unsigned short data5;
+
+ memcpy(&data0, &uuid->value.uuid128.data[0], 4);
+ memcpy(&data1, &uuid->value.uuid128.data[4], 2);
+ memcpy(&data2, &uuid->value.uuid128.data[6], 2);
+ memcpy(&data3, &uuid->value.uuid128.data[8], 2);
+ memcpy(&data4, &uuid->value.uuid128.data[10], 4);
+ memcpy(&data5, &uuid->value.uuid128.data[14], 2);
+
+ printf("%.*sUUID128 : 0x%.8x-%.4x-%.4x-%.4x-%.8x-%.4x\n",
+ indent, indent_spaces,
+ ntohl(data0), ntohs(data1), ntohs(data2),
+ ntohs(data3), ntohl(data4), ntohs(data5));
+ } else
+ printf("%.*sEnum type of UUID not set\n",
+ indent, indent_spaces);
+ } else
+ printf("%.*sNull passed to print UUID\n",
+ indent, indent_spaces);
+}
+
+/*
+ * Parse a sequence of data elements (i.e. a list)
+ */
+static void printf_dataseq(sdp_data_t * pData, struct attrib_context *context, int indent)
+{
+ sdp_data_t *sdpdata = NULL;
+
+ sdpdata = pData;
+ if (sdpdata) {
+ context->member_index = 0;
+ do {
+ sdp_data_printf(sdpdata, context, indent + 2);
+ sdpdata = sdpdata->next;
+ context->member_index++;
+ } while (sdpdata);
+ } else {
+ printf("%.*sBroken dataseq link\n", indent, indent_spaces);
+ }
+}
+
+/*
+ * Parse a single data element (either in the attribute or in a data
+ * sequence).
+ */
+static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, int indent)
+{
+ char *member_name = NULL;
+
+ /* Find member name. Almost black magic ;-) */
+ if (context && context->attrib && context->attrib->members &&
+ context->member_index < context->attrib->member_max) {
+ member_name = context->attrib->members[context->member_index].name;
+ }
+
+ switch (sdpdata->dtd) {
+ case SDP_DATA_NIL:
+ printf("%.*sNil\n", indent, indent_spaces);
+ break;
+ case SDP_BOOL:
+ case SDP_UINT8:
+ case SDP_UINT16:
+ case SDP_UINT32:
+ case SDP_UINT64:
+ case SDP_UINT128:
+ case SDP_INT8:
+ case SDP_INT16:
+ case SDP_INT32:
+ case SDP_INT64:
+ case SDP_INT128:
+ if (member_name) {
+ printf("%.*s%s (Integer) : 0x%x\n",
+ indent, indent_spaces, member_name, sdpdata->val.uint32);
+ } else {
+ printf("%.*sInteger : 0x%x\n", indent, indent_spaces,
+ sdpdata->val.uint32);
+ }
+ break;
+
+ case SDP_UUID16:
+ case SDP_UUID32:
+ case SDP_UUID128:
+ //printf("%.*sUUID\n", indent, indent_spaces);
+ sdp_uuid_printf(&sdpdata->val.uuid, context, indent);
+ break;
+
+ case SDP_TEXT_STR8:
+ case SDP_TEXT_STR16:
+ case SDP_TEXT_STR32:
+ if (sdpdata->unitSize > strlen(sdpdata->val.str)) {
+ int i;
+ printf("%.*sData :", indent, indent_spaces);
+ for (i = 0; i < sdpdata->unitSize; i++)
+ printf(" %02x", (unsigned char) sdpdata->val.str[i]);
+ printf("\n");
+ } else
+ printf("%.*sText : \"%s\"\n", indent, indent_spaces, sdpdata->val.str);
+ break;
+ case SDP_URL_STR8:
+ case SDP_URL_STR16:
+ case SDP_URL_STR32:
+ printf("%.*sURL : %s\n", indent, indent_spaces, sdpdata->val.str);
+ break;
+
+ case SDP_SEQ8:
+ case SDP_SEQ16:
+ case SDP_SEQ32:
+ printf("%.*sData Sequence\n", indent, indent_spaces);
+ printf_dataseq(sdpdata->val.dataseq, context, indent);
+ break;
+
+ case SDP_ALT8:
+ case SDP_ALT16:
+ case SDP_ALT32:
+ printf("%.*sData Sequence Alternates\n", indent, indent_spaces);
+ printf_dataseq(sdpdata->val.dataseq, context, indent);
+ break;
+ }
+}
+
+/*
+ * Parse a single attribute.
+ */
+static void print_tree_attr_func(void *value, void *userData)
+{
+ sdp_data_t *sdpdata = NULL;
+ 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;
+ attrId = sdpdata->attrId;
+ /* Search amongst the generic attributes */
+ for (i = 0; i < attrib_max; i++)
+ if (attrib_names[i].num == attrId) {
+ attrDef = &attrib_names[i];
+ break;
+ }
+ /* Search amongst the specific attributes of this service */
+ if ((attrDef == NULL) && (service->service != NULL) &&
+ (service->service->attribs != NULL)) {
+ struct attrib_def *svc_attribs = service->service->attribs;
+ int svc_attrib_max = service->service->attrib_max;
+ for (i = 0; i < svc_attrib_max; i++)
+ if (svc_attribs[i].num == attrId) {
+ attrDef = &svc_attribs[i];
+ break;
+ }
+ }
+
+ if (attrDef)
+ printf("Attribute Identifier : 0x%x - %s\n", attrId, attrDef->name);
+ else
+ printf("Attribute Identifier : 0x%x\n", attrId);
+ /* Build context */
+ context.service = service->service;
+ context.attrib = attrDef;
+ context.member_index = 0;
+ /* Parse attribute members */
+ if (sdpdata)
+ sdp_data_printf(sdpdata, &context, 2);
+ else
+ printf(" NULL value\n");
+ /* Update service */
+ service->service = context.service;
+}
+
+/*
+ * Main entry point of this library. Parse a SDP record.
+ * We assume the record has already been read, parsed and cached
+ * locally. Jean II
+ */
+static void print_tree_attr(sdp_record_t *rec)
+{
+ if (rec && rec->attrlist) {
+ struct service_context service = { NULL };
+ sdp_list_foreach(rec->attrlist, print_tree_attr_func, &service);
+ }
+}
+
+static void print_raw_data(sdp_data_t *data, int indent)
+{
+ struct uuid_def *def;
+ int i, hex;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+
+ switch (data->dtd) {
+ case SDP_DATA_NIL:
+ printf("NIL\n");
+ break;
+ case SDP_BOOL:
+ printf("Bool %s\n", data->val.uint8 ? "True" : "False");
+ break;
+ case SDP_UINT8:
+ printf("UINT8 0x%02x\n", data->val.uint8);
+ break;
+ case SDP_UINT16:
+ printf("UINT16 0x%04x\n", data->val.uint16);
+ break;
+ case SDP_UINT32:
+ printf("UINT32 0x%08x\n", data->val.uint32);
+ break;
+ case SDP_UINT64:
+ printf("UINT64 0x%016jx\n", data->val.uint64);
+ break;
+ case SDP_UINT128:
+ printf("UINT128 ...\n");
+ break;
+ case SDP_INT8:
+ printf("INT8 %d\n", data->val.int8);
+ break;
+ case SDP_INT16:
+ printf("INT16 %d\n", data->val.int16);
+ break;
+ case SDP_INT32:
+ printf("INT32 %d\n", data->val.int32);
+ break;
+ case SDP_INT64:
+ printf("INT64 %jd\n", data->val.int64);
+ break;
+ case SDP_INT128:
+ printf("INT128 ...\n");
+ break;
+ case SDP_UUID16:
+ case SDP_UUID32:
+ case SDP_UUID128:
+ switch (data->val.uuid.type) {
+ case SDP_UUID16:
+ def = NULL;
+ for (i = 0; i < uuid16_max; i++)
+ if (uuid16_names[i].num == data->val.uuid.value.uuid16) {
+ def = &uuid16_names[i];
+ break;
+ }
+ if (def)
+ printf("UUID16 0x%04x - %s\n", data->val.uuid.value.uuid16, def->name);
+ else
+ printf("UUID16 0x%04x\n", data->val.uuid.value.uuid16);
+ break;
+ case SDP_UUID32:
+ def = NULL;
+ if (!(data->val.uuid.value.uuid32 & 0xffff0000)) {
+ uint16_t value = data->val.uuid.value.uuid32;
+ for (i = 0; i < uuid16_max; i++)
+ if (uuid16_names[i].num == value) {
+ def = &uuid16_names[i];
+ break;
+ }
+ }
+ if (def)
+ printf("UUID32 0x%08x - %s\n", data->val.uuid.value.uuid32, def->name);
+ else
+ printf("UUID32 0x%08x\n", data->val.uuid.value.uuid32);
+ break;
+ case SDP_UUID128:
+ printf("UUID128 ");
+ for (i = 0; i < 16; i++) {
+ switch (i) {
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ printf("-");
+ break;
+ }
+ printf("%02x", (unsigned char ) data->val.uuid.value.uuid128.data[i]);
+ }
+ printf("\n");
+ break;
+ default:
+ printf("UUID type 0x%02x\n", data->val.uuid.type);
+ break;
+ }
+ break;
+ case SDP_TEXT_STR8:
+ case SDP_TEXT_STR16:
+ case SDP_TEXT_STR32:
+ hex = 0;
+ for (i = 0; i < data->unitSize; i++) {
+ if (i == (data->unitSize - 1) && data->val.str[i] == '\0')
+ break;
+ if (!isprint(data->val.str[i])) {
+ hex = 1;
+ break;
+ }
+ }
+ if (hex) {
+ printf("Data");
+ for (i = 0; i < data->unitSize; i++)
+ printf(" %02x", (unsigned char) data->val.str[i]);
+ } else {
+ printf("String ");
+ for (i = 0; i < data->unitSize; i++)
+ printf("%c", data->val.str[i]);
+ }
+ printf("\n");
+ break;
+ case SDP_URL_STR8:
+ case SDP_URL_STR16:
+ case SDP_URL_STR32:
+ printf("URL %s\n", data->val.str);
+ break;
+ case SDP_SEQ8:
+ case SDP_SEQ16:
+ case SDP_SEQ32:
+ printf("Sequence\n");
+ print_raw_data(data->val.dataseq, indent + 1);
+ break;
+ case SDP_ALT8:
+ case SDP_ALT16:
+ case SDP_ALT32:
+ printf("Alternate\n");
+ print_raw_data(data->val.dataseq, indent + 1);
+ break;
+ default:
+ printf("Unknown type 0x%02x\n", data->dtd);
+ break;
+ }
+
+ print_raw_data(data->next, indent);
+}
+
+static void print_raw_attr_func(void *value, void *userData)
+{
+ sdp_data_t *data = (sdp_data_t *) value;
+ struct attrib_def *def = NULL;
+ int i;
+
+ /* Search amongst the generic attributes */
+ for (i = 0; i < attrib_max; i++)
+ if (attrib_names[i].num == data->attrId) {
+ def = &attrib_names[i];
+ break;
+ }
+
+ if (def)
+ printf("\tAttribute 0x%04x - %s\n", data->attrId, def->name);
+ else
+ printf("\tAttribute 0x%04x\n", data->attrId);
+
+ if (data)
+ print_raw_data(data, 2);
+ else
+ printf(" NULL value\n");
+}
+
+static void print_raw_attr(sdp_record_t *rec)
+{
+ if (rec && rec->attrlist) {
+ printf("Sequence\n");
+ sdp_list_foreach(rec->attrlist, print_raw_attr_func, 0);
+ }
+}
+
+/*
+ * 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)
+{
+ sdp_list_t *attrid_list;
+ uint32_t range = 0x0000ffff;
+ sdp_record_t *rec;
+ int ret;
+
+ /* Get the old SDP record */
+ attrid_list = sdp_list_append(NULL, &range);
+ rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attrid_list);
+ sdp_list_free(attrid_list, NULL);
+
+ if (!rec) {
+ printf("Service get request failed.\n");
+ return -1;
+ }
+
+ /* Check the type of attribute */
+ if (!strncasecmp(value, "u0x", 3)) {
+ /* UUID16 */
+ uint16_t value_int = 0;
+ uuid_t value_uuid;
+ value_int = strtoul(value + 3, NULL, 16);
+ sdp_uuid16_create(&value_uuid, value_int);
+ printf("Adding attrib 0x%X uuid16 0x%X to record 0x%X\n",
+ attrib, value_int, handle);
+
+ sdp_attr_add_new(rec, attrib, SDP_UUID16, &value_uuid.value.uuid16);
+ } else if (!strncasecmp(value, "0x", 2)) {
+ /* 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);
+
+ sdp_attr_add_new(rec, attrib, SDP_UINT32, &value_int);
+ } else {
+ /* String */
+ printf("Adding attrib 0x%X string \"%s\" to record 0x%X\n",
+ attrib, value, handle);
+
+ /* Add/Update our attribute to the record */
+ sdp_attr_add_new(rec, attrib, SDP_TEXT_STR8, value);
+ }
+
+ /* Update on the server */
+ ret = sdp_device_record_update(sess, &interface, rec);
+ if (ret < 0)
+ printf("Service Record update failed (%d).\n", errno);
+ sdp_record_free(rec);
+ return ret;
+}
+
+static struct option set_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *set_help =
+ "Usage:\n"
+ "\tget record_handle attrib_id attrib_value\n";
+
+/*
+ * Add an attribute to an existing SDP record on the local SDP server
+ */
+static int cmd_setattr(int argc, char **argv)
+{
+ int opt, status;
+ uint32_t handle;
+ uint16_t attrib;
+ sdp_session_t *sess;
+
+ for_each_opt(opt, set_options, NULL) {
+ switch(opt) {
+ default:
+ printf(set_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 3) {
+ printf(set_help);
+ return -1;
+ }
+
+ /* Convert command line args */
+ handle = strtoul(argv[0], NULL, 16);
+ attrib = strtoul(argv[1], NULL, 16);
+
+ /* Do it */
+ sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
+ if (!sess)
+ return -1;
+
+ status = set_attrib(sess, handle, attrib, argv[2]);
+ sdp_close(sess);
+
+ return status;
+}
+
+/*
+ * We do only simple data sequences. Sequence of sequences is a pain ;-)
+ * Jean II
+ */
+static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attrib, int argc, char **argv)
+{
+ sdp_list_t *attrid_list;
+ uint32_t range = 0x0000ffff;
+ sdp_record_t *rec;
+ sdp_data_t *pSequenceHolder = NULL;
+ void **dtdArray;
+ void **valueArray;
+ void **allocArray;
+ uint8_t uuid16 = SDP_UUID16;
+ uint8_t uint32 = SDP_UINT32;
+ uint8_t str8 = SDP_TEXT_STR8;
+ int i, ret = 0;
+
+ /* Get the old SDP record */
+ attrid_list = sdp_list_append(NULL, &range);
+ rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid_list);
+ sdp_list_free(attrid_list, NULL);
+
+ if (!rec) {
+ printf("Service get request failed.\n");
+ return -1;
+ }
+
+ /* Create arrays */
+ dtdArray = (void **)malloc(argc * sizeof(void *));
+ valueArray = (void **)malloc(argc * sizeof(void *));
+ allocArray = (void **)malloc(argc * sizeof(void *));
+
+ /* Loop on all args, add them in arrays */
+ for (i = 0; i < argc; i++) {
+ /* Check the type of attribute */
+ if (!strncasecmp(argv[i], "u0x", 3)) {
+ /* UUID16 */
+ uint16_t value_int = strtoul((argv[i]) + 3, NULL, 16);
+ uuid_t *value_uuid = (uuid_t *) malloc(sizeof(uuid_t));
+ allocArray[i] = value_uuid;
+ sdp_uuid16_create(value_uuid, value_int);
+
+ printf("Adding uuid16 0x%X to record 0x%X\n", value_int, handle);
+ dtdArray[i] = &uuid16;
+ valueArray[i] = &value_uuid->value.uuid16;
+ } else if (!strncasecmp(argv[i], "0x", 2)) {
+ /* Int */
+ uint32_t *value_int = (uint32_t *) malloc(sizeof(int));
+ allocArray[i] = value_int;
+ *value_int = strtoul((argv[i]) + 2, NULL, 16);
+
+ printf("Adding int 0x%X to record 0x%X\n", *value_int, handle);
+ dtdArray[i] = &uint32;
+ valueArray[i] = value_int;
+ } else {
+ /* String */
+ printf("Adding string \"%s\" to record 0x%X\n", argv[i], handle);
+ dtdArray[i] = &str8;
+ valueArray[i] = argv[i];
+ }
+ }
+
+ /* Add this sequence to the attrib list */
+ pSequenceHolder = sdp_seq_alloc(dtdArray, valueArray, argc);
+ if (pSequenceHolder) {
+ sdp_attr_replace(rec, attrib, pSequenceHolder);
+
+ /* Update on the server */
+ ret = sdp_device_record_update(session, &interface, rec);
+ if (ret < 0)
+ printf("Service Record update failed (%d).\n", errno);
+ } else
+ printf("Failed to create pSequenceHolder\n");
+
+ /* Cleanup */
+ for (i = 0; i < argc; i++)
+ free(allocArray[i]);
+
+ free(dtdArray);
+ free(valueArray);
+ free(allocArray);
+
+ sdp_record_free(rec);
+
+ return ret;
+}
+
+static struct option seq_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *seq_help =
+ "Usage:\n"
+ "\tget record_handle attrib_id attrib_values\n";
+
+/*
+ * Add an attribute sequence to an existing SDP record
+ * on the local SDP server
+ */
+static int cmd_setseq(int argc, char **argv)
+{
+ int opt, status;
+ uint32_t handle;
+ uint16_t attrib;
+ sdp_session_t *sess;
+
+ for_each_opt(opt, seq_options, NULL) {
+ switch(opt) {
+ default:
+ printf(seq_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 3) {
+ printf(seq_help);
+ return -1;
+ }
+
+ /* Convert command line args */
+ handle = strtoul(argv[0], NULL, 16);
+ attrib = strtoul(argv[1], NULL, 16);
+
+ argc -= 2;
+ argv += 2;
+
+ /* Do it */
+ sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
+ if (!sess)
+ return -1;
+
+ status = set_attribseq(sess, handle, attrib, argc, argv);
+ sdp_close(sess);
+
+ return status;
+}
+
+static void print_service_class(void *value, void *userData)
+{
+ char ServiceClassUUID_str[MAX_LEN_SERVICECLASS_UUID_STR];
+ uuid_t *uuid = (uuid_t *)value;
+
+ sdp_uuid2strn(uuid, UUID_str, MAX_LEN_UUID_STR);
+ sdp_svclass_uuid2strn(uuid, ServiceClassUUID_str, MAX_LEN_SERVICECLASS_UUID_STR);
+ if (uuid->type != SDP_UUID128)
+ printf(" \"%s\" (0x%s)\n", ServiceClassUUID_str, UUID_str);
+ else
+ printf(" UUID 128: %s\n", UUID_str);
+}
+
+static void print_service_desc(void *value, void *user)
+{
+ char str[MAX_LEN_PROTOCOL_UUID_STR];
+ sdp_data_t *p = (sdp_data_t *)value, *s;
+ int i = 0, proto = 0;
+
+ for (; p; p = p->next, i++) {
+ switch (p->dtd) {
+ case SDP_UUID16:
+ case SDP_UUID32:
+ case SDP_UUID128:
+ sdp_uuid2strn(&p->val.uuid, UUID_str, MAX_LEN_UUID_STR);
+ sdp_proto_uuid2strn(&p->val.uuid, str, sizeof(str));
+ proto = sdp_uuid_to_proto(&p->val.uuid);
+ printf(" \"%s\" (0x%s)\n", str, UUID_str);
+ break;
+ case SDP_UINT8:
+ if (proto == RFCOMM_UUID)
+ printf(" Channel: %d\n", p->val.uint8);
+ else
+ printf(" uint8: 0x%x\n", p->val.uint8);
+ break;
+ case SDP_UINT16:
+ if (proto == L2CAP_UUID) {
+ if (i == 1)
+ printf(" PSM: %d\n", p->val.uint16);
+ else
+ printf(" Version: 0x%04x\n", p->val.uint16);
+ } else if (proto == BNEP_UUID)
+ if (i == 1)
+ printf(" Version: 0x%04x\n", p->val.uint16);
+ else
+ printf(" uint16: 0x%x\n", p->val.uint16);
+ else
+ printf(" uint16: 0x%x\n", p->val.uint16);
+ break;
+ case SDP_SEQ16:
+ printf(" SEQ16:");
+ for (s = p->val.dataseq; s; s = s->next)
+ printf(" %x", s->val.uint16);
+ printf("\n");
+ break;
+ case SDP_SEQ8:
+ printf(" SEQ8:");
+ for (s = p->val.dataseq; s; s = s->next)
+ printf(" %x", s->val.uint8);
+ printf("\n");
+ break;
+ default:
+ printf(" FIXME: dtd=0%x\n", p->dtd);
+ break;
+ }
+ }
+}
+
+static void print_lang_attr(void *value, void *user)
+{
+ sdp_lang_attr_t *lang = (sdp_lang_attr_t *)value;
+ printf(" code_ISO639: 0x%02x\n", lang->code_ISO639);
+ printf(" encoding: 0x%02x\n", lang->encoding);
+ printf(" base_offset: 0x%02x\n", lang->base_offset);
+}
+
+static void print_access_protos(void *value, void *userData)
+{
+ sdp_list_t *protDescSeq = (sdp_list_t *)value;
+ sdp_list_foreach(protDescSeq, print_service_desc, 0);
+}
+
+static void print_profile_desc(void *value, void *userData)
+{
+ sdp_profile_desc_t *desc = (sdp_profile_desc_t *)value;
+ char str[MAX_LEN_PROFILEDESCRIPTOR_UUID_STR];
+
+ sdp_uuid2strn(&desc->uuid, UUID_str, MAX_LEN_UUID_STR);
+ sdp_profile_uuid2strn(&desc->uuid, str, MAX_LEN_PROFILEDESCRIPTOR_UUID_STR);
+
+ printf(" \"%s\" (0x%s)\n", str, UUID_str);
+ if (desc->version)
+ printf(" Version: 0x%04x\n", desc->version);
+}
+
+/*
+ * Parse a SDP record in user friendly form.
+ */
+static void print_service_attr(sdp_record_t *rec)
+{
+ sdp_list_t *list = 0, *proto = 0;
+
+ sdp_record_print(rec);
+
+ printf("Service RecHandle: 0x%x\n", rec->handle);
+
+ if (sdp_get_service_classes(rec, &list) == 0) {
+ printf("Service Class ID List:\n");
+ sdp_list_foreach(list, print_service_class, 0);
+ sdp_list_free(list, free);
+ }
+ if (sdp_get_access_protos(rec, &proto) == 0) {
+ printf("Protocol Descriptor List:\n");
+ sdp_list_foreach(proto, print_access_protos, 0);
+ sdp_list_foreach(proto, (sdp_list_func_t)sdp_list_free, 0);
+ sdp_list_free(proto, 0);
+ }
+ if (sdp_get_lang_attr(rec, &list) == 0) {
+ printf("Language Base Attr List:\n");
+ sdp_list_foreach(list, print_lang_attr, 0);
+ sdp_list_free(list, free);
+ }
+ if (sdp_get_profile_descs(rec, &list) == 0) {
+ printf("Profile Descriptor List:\n");
+ sdp_list_foreach(list, print_profile_desc, 0);
+ sdp_list_free(list, free);
+ }
+}
+
+/*
+ * Support for Service (de)registration
+ */
+typedef struct {
+ uint32_t handle;
+ char *name;
+ char *provider;
+ char *desc;
+ unsigned int class;
+ unsigned int profile;
+ uint16_t psm;
+ uint8_t channel;
+ uint8_t network;
+} svc_info_t;
+
+static void add_lang_attr(sdp_record_t *r)
+{
+ sdp_lang_attr_t base_lang;
+ sdp_list_t *langs = 0;
+
+ /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
+ base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
+ base_lang.encoding = 106;
+ base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
+ langs = sdp_list_append(0, &base_lang);
+ sdp_set_lang_attr(r, langs);
+ sdp_list_free(langs, 0);
+}
+
+static int add_sp(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
+ uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
+ sdp_profile_desc_t profile;
+ sdp_record_t record;
+ uint8_t u8 = si->channel ? si->channel : 1;
+ sdp_data_t *channel;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+ sdp_list_free(root, 0);
+
+ sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &sp_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+ sdp_list_free(svclass_id, 0);
+
+ sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
+ profile.version = 0x0100;
+ profiles = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, profiles);
+ sdp_list_free(profiles, 0);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ add_lang_attr(&record);
+
+ sdp_set_info_attr(&record, "Serial Port", 0, "COM Port");
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("Serial Port service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_dun(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
+ uuid_t rootu, dun, gn, l2cap, rfcomm;
+ sdp_profile_desc_t profile;
+ sdp_list_t *proto[2];
+ sdp_record_t record;
+ uint8_t u8 = si->channel ? si->channel : 2;
+ sdp_data_t *channel;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&rootu, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &rootu);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &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(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Dial-Up Networking", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("Dial-Up Networking service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_fax(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, fax_uuid, tel_uuid, l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint8_t u8 = si->channel? si->channel : 3;
+ sdp_data_t *channel;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&fax_uuid, FAX_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &fax_uuid);
+ sdp_uuid16_create(&tel_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &tel_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, FAX_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Fax", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+ printf("Fax service registered\n");
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+ return ret;
+}
+
+static int add_lan(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint8_t u8 = si->channel ? si->channel : 4;
+ sdp_data_t *channel;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&svclass_uuid, LAN_ACCESS_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, LAN_ACCESS_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "LAN Access over PPP", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("LAN Access service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_headset(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint8_t u8 = si->channel ? si->channel : 5;
+ sdp_data_t *channel;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Headset", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("Headset service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_handsfree(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint8_t u8 = si->channel ? si->channel : 6;
+ uint16_t u16 = 0x31;
+ sdp_data_t *channel, *features;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+ profile.version = 0x0101;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ features = sdp_data_alloc(SDP_UINT16, &u16);
+ sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Handsfree", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("Handsfree service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_handsfree_ag(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint8_t u8 = si->channel ? si->channel : 7;
+ uint16_t u16 = 0x17;
+ sdp_data_t *channel, *features;
+ uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
+ sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ features = sdp_data_alloc(SDP_UINT16, &u16);
+ sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
+
+ sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+ if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("Handsfree AG service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_simaccess(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint8_t u8 = si->channel? si->channel : 8;
+ uint16_t u16 = 0x31;
+ sdp_data_t *channel, *features;
+ int ret = 0;
+
+ memset((void *)&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&svclass_uuid, SAP_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
+ profile.version = 0x0101;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ features = sdp_data_alloc(SDP_UINT16, &u16);
+ sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "SIM Access", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("SIM Access service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_opush(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[3];
+ sdp_record_t record;
+ uint8_t chan = si->channel ? si->channel : 9;
+ sdp_data_t *channel;
+ uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ //uint8_t formats[] = { 0xff };
+ void *dtds[sizeof(formats)], *values[sizeof(formats)];
+ int i;
+ uint8_t dtd = SDP_UINT8;
+ sdp_data_t *sflist;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &opush_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[2] = sdp_list_append(0, &obex_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ for (i = 0; i < sizeof(formats); i++) {
+ dtds[i] = &dtd;
+ values[i] = &formats[i];
+ }
+ sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
+ sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
+
+ sdp_set_info_attr(&record, "OBEX Object Push", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("OBEX Object Push service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(proto[2], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_ftp(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, ftrn_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[3];
+ sdp_record_t record;
+ uint8_t u8 = si->channel ? si->channel: 10;
+ sdp_data_t *channel;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&ftrn_uuid, OBEX_FILETRANS_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &ftrn_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, OBEX_FILETRANS_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &u8);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[2] = sdp_list_append(0, &obex_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "OBEX File Transfer", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("OBEX File Transfer service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(proto[2], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_directprint(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[3];
+ sdp_record_t record;
+ uint8_t chan = si->channel ? si->channel : 12;
+ sdp_data_t *channel;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&opush_uuid, DIRECT_PRINTING_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &opush_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, BASIC_PRINTING_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[2] = sdp_list_append(0, &obex_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Direct Printing", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("Direct Printing service registered\n");
+
+end:
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(proto[2], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_nap(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint16_t lp = 0x000f, ver = 0x0100;
+ sdp_data_t *psm, *version;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&ftrn_uuid, NAP_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &ftrn_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
+ proto[1] = sdp_list_append(0, &bnep_uuid);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+
+ {
+ uint16_t ptype[4] = { 0x0010, 0x0020, 0x0030, 0x0040 };
+ sdp_data_t *head, *pseq;
+ int p;
+
+ for (p = 0, head = NULL; p < 4; p++) {
+ sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
+ head = sdp_seq_append(head, data);
+ }
+ pseq = sdp_data_alloc(SDP_SEQ16, head);
+ proto[1] = sdp_list_append(proto[1], pseq);
+ }
+
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Network Access Point Service", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("NAP service registered\n");
+
+end:
+ sdp_data_free(version);
+ sdp_data_free(psm);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_gn(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint16_t lp = 0x000f, ver = 0x0100;
+ sdp_data_t *psm, *version;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&ftrn_uuid, GN_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &ftrn_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
+ proto[1] = sdp_list_append(0, &bnep_uuid);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Group Network Service", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("GN service registered\n");
+
+end:
+ sdp_data_free(version);
+ sdp_data_free(psm);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_panu(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint16_t lp = 0x000f, ver = 0x0100;
+ sdp_data_t *psm, *version;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+ sdp_list_free(root, NULL);
+
+ sdp_uuid16_create(&ftrn_uuid, PANU_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &ftrn_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+ sdp_list_free(svclass_id, NULL);
+
+ sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+ sdp_list_free(pfseq, NULL);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(NULL, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
+ proto[1] = sdp_list_append(NULL, &bnep_uuid);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "PAN User", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("PANU service registered\n");
+
+end:
+ sdp_data_free(version);
+ sdp_data_free(psm);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_hid_keyb(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[3];
+ sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
+ int i;
+ uint8_t dtd = SDP_UINT16;
+ uint8_t dtd2 = SDP_UINT8;
+ uint8_t dtd_data = SDP_TEXT_STR8;
+ void *dtds[2];
+ void *values[2];
+ void *dtds2[2];
+ void *values2[2];
+ int leng[2];
+ uint8_t hid_spec_type = 0x22;
+ uint16_t hid_attr_lang[] = { 0x409, 0x100 };
+ static const uint16_t ctrl = 0x11;
+ static const uint16_t intr = 0x13;
+ static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d, 0x01, 0x01 };
+ static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40, 0x01, 0x01 };
+ const uint8_t hid_spec[] = {
+ 0x05, 0x01, // usage page
+ 0x09, 0x06, // keyboard
+ 0xa1, 0x01, // key codes
+ 0x85, 0x01, // minimum
+ 0x05, 0x07, // max
+ 0x19, 0xe0, // logical min
+ 0x29, 0xe7, // logical max
+ 0x15, 0x00, // report size
+ 0x25, 0x01, // report count
+ 0x75, 0x01, // input data variable absolute
+ 0x95, 0x08, // report count
+ 0x81, 0x02, // report size
+ 0x75, 0x08,
+ 0x95, 0x01,
+ 0x81, 0x01,
+ 0x75, 0x01,
+ 0x95, 0x05,
+ 0x05, 0x08,
+ 0x19, 0x01,
+ 0x29, 0x05,
+ 0x91, 0x02,
+ 0x75, 0x03,
+ 0x95, 0x01,
+ 0x91, 0x01,
+ 0x75, 0x08,
+ 0x95, 0x06,
+ 0x15, 0x00,
+ 0x26, 0xff,
+ 0x00, 0x05,
+ 0x07, 0x19,
+ 0x00, 0x2a,
+ 0xff, 0x00,
+ 0x81, 0x00,
+ 0x75, 0x01,
+ 0x95, 0x01,
+ 0x15, 0x00,
+ 0x25, 0x01,
+ 0x05, 0x0c,
+ 0x09, 0xb8,
+ 0x81, 0x06,
+ 0x09, 0xe2,
+ 0x81, 0x06,
+ 0x09, 0xe9,
+ 0x81, 0x02,
+ 0x09, 0xea,
+ 0x81, 0x02,
+ 0x75, 0x01,
+ 0x95, 0x04,
+ 0x81, 0x01,
+ 0xc0 // end tag
+ };
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ add_lang_attr(&record);
+
+ sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &hidkb_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ /* protocols */
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[1] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &ctrl);
+ proto[1] = sdp_list_append(proto[1], psm);
+ apseq = sdp_list_append(0, proto[1]);
+
+ sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+ proto[2] = sdp_list_append(0, &hidp_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ /* additional protocols */
+ proto[1] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &intr);
+ proto[1] = sdp_list_append(proto[1], psm);
+ apseq = sdp_list_append(0, proto[1]);
+
+ sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+ proto[2] = sdp_list_append(0, &hidp_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_add_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "HID Keyboard", NULL, NULL);
+
+ for (i = 0; i < sizeof(hid_attr) / 2; i++)
+ sdp_attr_add_new(&record,
+ SDP_ATTR_HID_DEVICE_RELEASE_NUMBER + i,
+ SDP_UINT16, &hid_attr[i]);
+
+ dtds[0] = &dtd2;
+ values[0] = &hid_spec_type;
+ dtds[1] = &dtd_data;
+ values[1] = (uint8_t *) hid_spec;
+ leng[0] = 0;
+ leng[1] = sizeof(hid_spec);
+ hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
+ hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
+ sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
+
+ for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
+ dtds2[i] = &dtd;
+ values2[i] = &hid_attr_lang[i];
+ }
+
+ lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
+ lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
+ sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
+
+ for (i = 0; i < sizeof(hid_attr2) / 2 - 1; i++)
+ sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP + i,
+ SDP_UINT16, &hid_attr2[i + 1]);
+
+ if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("HID keyboard service registered\n");
+
+ return 0;
+}
+
+static int add_hid_wiimote(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, hid_uuid, l2cap_uuid, hidp_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[3];
+ sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
+ int i;
+ uint8_t dtd = SDP_UINT16;
+ uint8_t dtd2 = SDP_UINT8;
+ uint8_t dtd_data = SDP_TEXT_STR8;
+ void *dtds[2];
+ void *values[2];
+ void *dtds2[2];
+ void *values2[2];
+ int leng[2];
+ uint8_t hid_spec_type = 0x22;
+ uint16_t hid_attr_lang[] = { 0x409, 0x100 };
+ uint16_t ctrl = 0x11, intr = 0x13;
+ uint16_t hid_release = 0x0100, parser_version = 0x0111;
+ uint8_t subclass = 0x04, country = 0x33;
+ uint8_t virtual_cable = 0, reconnect = 1, sdp_disable = 0;
+ uint8_t battery = 1, remote_wakeup = 1;
+ uint16_t profile_version = 0x0100, superv_timeout = 0x0c80;
+ uint8_t norm_connect = 0, boot_device = 0;
+ const uint8_t hid_spec[] = {
+ 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
+ 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
+ 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
+ 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
+ 0xc0, 0x00
+ };
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&hid_uuid, HID_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &hid_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[1] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &ctrl);
+ proto[1] = sdp_list_append(proto[1], psm);
+ apseq = sdp_list_append(0, proto[1]);
+
+ sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+ proto[2] = sdp_list_append(0, &hidp_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ proto[1] = sdp_list_append(0, &l2cap_uuid);
+ psm = sdp_data_alloc(SDP_UINT16, &intr);
+ proto[1] = sdp_list_append(proto[1], psm);
+ apseq = sdp_list_append(0, proto[1]);
+
+ sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+ proto[2] = sdp_list_append(0, &hidp_uuid);
+ apseq = sdp_list_append(apseq, proto[2]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_add_access_protos(&record, aproto);
+
+ add_lang_attr(&record);
+
+ sdp_set_info_attr(&record, "Nintendo RVL-CNT-01",
+ "Nintendo", "Nintendo RVL-CNT-01");
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER,
+ SDP_UINT16, &hid_release);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_PARSER_VERSION,
+ SDP_UINT16, &parser_version);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_SUBCLASS,
+ SDP_UINT8, &subclass);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_COUNTRY_CODE,
+ SDP_UINT8, &country);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_VIRTUAL_CABLE,
+ SDP_BOOL, &virtual_cable);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_RECONNECT_INITIATE,
+ SDP_BOOL, &reconnect);
+
+ dtds[0] = &dtd2;
+ values[0] = &hid_spec_type;
+ dtds[1] = &dtd_data;
+ values[1] = (uint8_t *) hid_spec;
+ leng[0] = 0;
+ leng[1] = sizeof(hid_spec);
+ hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
+ hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
+ sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
+
+ for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
+ dtds2[i] = &dtd;
+ values2[i] = &hid_attr_lang[i];
+ }
+
+ lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
+ lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
+ sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE,
+ SDP_BOOL, &sdp_disable);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_BATTERY_POWER,
+ SDP_BOOL, &battery);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP,
+ SDP_BOOL, &remote_wakeup);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_PROFILE_VERSION,
+ SDP_UINT16, &profile_version);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_SUPERVISION_TIMEOUT,
+ SDP_UINT16, &superv_timeout);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_NORMALLY_CONNECTABLE,
+ SDP_BOOL, &norm_connect);
+
+ sdp_attr_add_new(&record, SDP_ATTR_HID_BOOT_DEVICE,
+ SDP_BOOL, &boot_device);
+
+ if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("Wii-Mote service registered\n");
+
+ return 0;
+}
+
+static int add_cip(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, cmtp, cip;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint16_t psm = si->psm ? si->psm : 0x1001;
+ uint8_t netid = si->network ? si->network : 0x02; // 0x02 = ISDN, 0x03 = GSM
+ sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&cip, CIP_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &cip);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, CIP_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ apseq = sdp_list_append(0, proto[0]);
+ proto[0] = sdp_list_append(proto[0], sdp_data_alloc(SDP_UINT16, &psm));
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&cmtp, CMTP_UUID);
+ proto[1] = sdp_list_append(0, &cmtp);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+ sdp_set_info_attr(&record, "Common ISDN Access", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("CIP service registered\n");
+
+end:
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_data_free(network);
+
+ return ret;
+}
+
+static int add_ctp(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, tcsbin, ctp;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint8_t netid = si->network ? si->network : 0x02; // 0x01-0x07 cf. p120 profile document
+ sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&ctp, CORDLESS_TELEPHONY_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &ctp);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, CORDLESS_TELEPHONY_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&tcsbin, TCS_BIN_UUID);
+ proto[1] = sdp_list_append(0, &tcsbin);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+ sdp_set_info_attr(&record, "Cordless Telephony", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto end;
+ }
+
+ printf("CTP service registered\n");
+
+end:
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_data_free(network);
+
+ return ret;
+}
+
+static int add_a2source(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, avdtp, a2src;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ sdp_data_t *psm, *version;
+ uint16_t lp = 0x0019, ver = 0x0100;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &a2src);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&avdtp, AVDTP_UUID);
+ proto[1] = sdp_list_append(0, &avdtp);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Audio Source", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto done;
+ }
+
+ printf("Audio source service registered\n");
+
+done:
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_a2sink(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, avdtp, a2snk;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ sdp_data_t *psm, *version;
+ uint16_t lp = 0x0019, ver = 0x0100;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&a2snk, AUDIO_SINK_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &a2snk);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&avdtp, AVDTP_UUID);
+ proto[1] = sdp_list_append(0, &avdtp);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Audio Sink", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto done;
+ }
+
+ printf("Audio sink service registered\n");
+
+done:
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_avrct(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, avctp, avrct;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ sdp_data_t *psm, *version, *features;
+ uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &avrct);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&avctp, AVCTP_UUID);
+ proto[1] = sdp_list_append(0, &avctp);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ features = sdp_data_alloc(SDP_UINT16, &feat);
+ sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ sdp_set_info_attr(&record, "AVRCP CT", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto done;
+ }
+
+ printf("Remote control service registered\n");
+
+done:
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_avrtg(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, l2cap, avctp, avrtg;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ sdp_data_t *psm, *version, *features;
+ uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
+ int ret = 0;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &avrtg);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(0, &profile[0]);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap);
+ psm = sdp_data_alloc(SDP_UINT16, &lp);
+ proto[0] = sdp_list_append(proto[0], psm);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&avctp, AVCTP_UUID);
+ proto[1] = sdp_list_append(0, &avctp);
+ version = sdp_data_alloc(SDP_UINT16, &ver);
+ proto[1] = sdp_list_append(proto[1], version);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ features = sdp_data_alloc(SDP_UINT16, &feat);
+ sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ sdp_set_info_attr(&record, "AVRCP TG", 0, 0);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ ret = -1;
+ goto done;
+ }
+
+ printf("Remote target service registered\n");
+
+done:
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(aproto, 0);
+
+ return ret;
+}
+
+static int add_udi_ue(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass, *proto;
+ uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ uint8_t channel = si->channel ? si->channel: 18;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+ sdp_list_free(root, NULL);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(
+ sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_uuid16_create(&svclass_uuid, UDI_MT_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+ sdp_list_free(svclass, NULL);
+
+ sdp_set_info_attr(&record, "UDI UE", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("UDI UE service registered\n");
+
+ return 0;
+}
+
+static int add_udi_te(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass, *proto;
+ uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ uint8_t channel = si->channel ? si->channel: 19;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+ sdp_list_free(root, NULL);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(
+ sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_uuid16_create(&svclass_uuid, UDI_TA_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+ sdp_list_free(svclass, NULL);
+
+ sdp_set_info_attr(&record, "UDI TE", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("UDI TE service registered\n");
+
+ return 0;
+}
+
+static unsigned char sr1_uuid[] = { 0xbc, 0x19, 0x9c, 0x24, 0x95, 0x8b, 0x4c, 0xc0,
+ 0xa2, 0xcb, 0xfd, 0x8a, 0x30, 0xbf, 0x32, 0x06 };
+
+static int add_sr1(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass;
+ uuid_t root_uuid, svclass_uuid;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid128_create(&svclass_uuid, (void *) sr1_uuid);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_set_info_attr(&record, "TOSHIBA SR-1", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("Toshiba Speech Recognition SR-1 service record registered\n");
+
+ return 0;
+}
+
+static unsigned char syncmls_uuid[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
+
+static unsigned char syncmlc_uuid[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
+
+static int add_syncml(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass, *proto;
+ uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+ uint8_t channel = si->channel ? si->channel: 15;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid128_create(&svclass_uuid, (void *) syncmlc_uuid);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(
+ sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(NULL, &obex_uuid));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_set_info_attr(&record, "SyncML Client", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("SyncML Client service record registered\n");
+
+ return 0;
+}
+
+static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
+ 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
+
+static int add_activesync(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass, *proto;
+ uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ uint8_t channel = si->channel ? si->channel: 21;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(
+ sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_uuid128_create(&svclass_uuid, (void *) async_uuid);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_set_info_attr(&record, "Microsoft ActiveSync", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("ActiveSync service record registered\n");
+
+ return 0;
+}
+
+static unsigned char hotsync_uuid[] = { 0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5,
+ 0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C };
+
+static int add_hotsync(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass, *proto;
+ uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ uint8_t channel = si->channel ? si->channel: 22;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(
+ sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("HotSync service record registered\n");
+
+ return 0;
+}
+
+static unsigned char palmos_uuid[] = { 0xF5, 0xBE, 0xB6, 0x51, 0x41, 0x71, 0x40, 0x51,
+ 0xAC, 0xF5, 0x6C, 0xA7, 0x20, 0x22, 0x42, 0xF0 };
+
+static int add_palmos(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass;
+ uuid_t root_uuid, svclass_uuid;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid128_create(&svclass_uuid, (void *) palmos_uuid);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("PalmOS service record registered\n");
+
+ return 0;
+}
+
+static unsigned char nokid_uuid[] = { 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
+
+static int add_nokiaid(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass;
+ uuid_t root_uuid, svclass_uuid;
+ uint16_t verid = 0x005f;
+ sdp_data_t *version = sdp_data_alloc(SDP_UINT16, &verid);
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid128_create(&svclass_uuid, (void *) nokid_uuid);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_attr_add(&record, SDP_ATTR_SERVICE_VERSION, version);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ sdp_data_free(version);
+ return -1;
+ }
+
+ printf("Nokia ID service record registered\n");
+
+ return 0;
+}
+
+static unsigned char pcsuite_uuid[] = { 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
+
+static int add_pcsuite(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass, *proto;
+ uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
+ uint8_t channel = si->channel ? si->channel: 14;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(
+ sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_uuid128_create(&svclass_uuid, (void *) pcsuite_uuid);
+ svclass = sdp_list_append(NULL, &svclass_uuid);
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_set_info_attr(&record, "Nokia PC Suite", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("Nokia PC Suite service registered\n");
+
+ return 0;
+}
+
+static unsigned char nftp_uuid[] = { 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
+
+static unsigned char nsyncml_uuid[] = { 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
+
+static unsigned char ngage_uuid[] = { 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
+
+static unsigned char apple_uuid[] = { 0xf0, 0x72, 0x2e, 0x20, 0x0f, 0x8b, 0x4e, 0x90,
+ 0x8c, 0xc2, 0x1b, 0x46, 0xf5, 0xf2, 0xef, 0xe2 };
+
+static int add_apple(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root;
+ uuid_t root_uuid;
+ uint32_t attr783 = 0x00000000;
+ uint32_t attr785 = 0x00000002;
+ uint16_t attr786 = 0x1234;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_attr_add_new(&record, 0x0780, SDP_UUID128, (void *) apple_uuid);
+ sdp_attr_add_new(&record, 0x0781, SDP_TEXT_STR8, (void *) "Macmini");
+ sdp_attr_add_new(&record, 0x0782, SDP_TEXT_STR8, (void *) "PowerMac10,1");
+ sdp_attr_add_new(&record, 0x0783, SDP_UINT32, (void *) &attr783);
+ sdp_attr_add_new(&record, 0x0784, SDP_TEXT_STR8, (void *) "1.6.6f22");
+ sdp_attr_add_new(&record, 0x0785, SDP_UINT32, (void *) &attr785);
+ sdp_attr_add_new(&record, 0x0786, SDP_UUID16, (void *) &attr786);
+
+ sdp_set_info_attr(&record, "Apple Macintosh Attributes", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("Apple attribute service registered\n");
+
+ return 0;
+}
+
+static int add_isync(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_list_t *root, *svclass, *proto;
+ uuid_t root_uuid, svclass_uuid, serial_uuid, l2cap_uuid, rfcomm_uuid;
+ uint8_t channel = si->channel ? si->channel : 16;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto = sdp_list_append(proto, sdp_list_append(
+ sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_uuid16_create(&serial_uuid, SERIAL_PORT_SVCLASS_ID);
+ svclass = sdp_list_append(NULL, &serial_uuid);
+
+ sdp_uuid16_create(&svclass_uuid, APPLE_AGENT_SVCLASS_ID);
+ svclass = sdp_list_append(svclass, &svclass_uuid);
+
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_set_info_attr(&record, "AppleAgent", "Bluetooth acceptor", "Apple Computer Ltd.");
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ printf("Apple iSync service registered\n");
+
+ return 0;
+}
+
+static int add_semchla(sdp_session_t *session, svc_info_t *si)
+{
+ sdp_record_t record;
+ sdp_profile_desc_t profile;
+ sdp_list_t *root, *svclass, *proto, *profiles;
+ uuid_t root_uuid, service_uuid, l2cap_uuid, semchla_uuid;
+ uint16_t psm = 0xf0f9;
+
+ memset(&record, 0, sizeof(record));
+ record.handle = si->handle;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto = sdp_list_append(NULL, sdp_list_append(
+ sdp_list_append(NULL, &l2cap_uuid), sdp_data_alloc(SDP_UINT16, &psm)));
+
+ sdp_uuid32_create(&semchla_uuid, 0x8e770300);
+ proto = sdp_list_append(proto, sdp_list_append(NULL, &semchla_uuid));
+
+ sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
+
+ sdp_uuid32_create(&service_uuid, 0x8e771301);
+ svclass = sdp_list_append(NULL, &service_uuid);
+
+ sdp_set_service_classes(&record, svclass);
+
+ sdp_uuid32_create(&profile.uuid, 0x8e771302); // Headset
+ //sdp_uuid32_create(&profile.uuid, 0x8e771303); // Phone
+ profile.version = 0x0100;
+ profiles = sdp_list_append(NULL, &profile);
+ sdp_set_profile_descs(&record, profiles);
+
+ sdp_set_info_attr(&record, "SEMC HLA", NULL, NULL);
+
+ if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
+ printf("Service Record registration failed\n");
+ return -1;
+ }
+
+ /* SEMC High Level Authentication */
+ printf("SEMC HLA service registered\n");
+
+ return 0;
+}
+
+struct {
+ char *name;
+ uint32_t class;
+ int (*add)(sdp_session_t *sess, svc_info_t *si);
+ unsigned char *uuid;
+} service[] = {
+ { "DID", PNP_INFO_SVCLASS_ID, NULL, },
+
+ { "SP", SERIAL_PORT_SVCLASS_ID, add_sp },
+ { "DUN", DIALUP_NET_SVCLASS_ID, add_dun },
+ { "LAN", LAN_ACCESS_SVCLASS_ID, add_lan },
+ { "FAX", FAX_SVCLASS_ID, add_fax },
+ { "OPUSH", OBEX_OBJPUSH_SVCLASS_ID, add_opush },
+ { "FTP", OBEX_FILETRANS_SVCLASS_ID, add_ftp },
+ { "PRINT", DIRECT_PRINTING_SVCLASS_ID, add_directprint },
+
+ { "HS", HEADSET_SVCLASS_ID, add_headset },
+ { "HF", HANDSFREE_SVCLASS_ID, add_handsfree },
+ { "HFAG", HANDSFREE_AGW_SVCLASS_ID, add_handsfree_ag},
+ { "SAP", SAP_SVCLASS_ID, add_simaccess },
+
+ { "NAP", NAP_SVCLASS_ID, add_nap },
+ { "GN", GN_SVCLASS_ID, add_gn },
+ { "PANU", PANU_SVCLASS_ID, add_panu },
+
+ { "HCRP", HCR_SVCLASS_ID, NULL },
+ { "HID", HID_SVCLASS_ID, NULL },
+ { "KEYB", HID_SVCLASS_ID, add_hid_keyb },
+ { "WIIMOTE", HID_SVCLASS_ID, add_hid_wiimote },
+ { "CIP", CIP_SVCLASS_ID, add_cip },
+ { "CTP", CORDLESS_TELEPHONY_SVCLASS_ID, add_ctp },
+
+ { "A2SRC", AUDIO_SOURCE_SVCLASS_ID, add_a2source },
+ { "A2SNK", AUDIO_SINK_SVCLASS_ID, add_a2sink },
+ { "AVRCT", AV_REMOTE_SVCLASS_ID, add_avrct },
+ { "AVRTG", AV_REMOTE_TARGET_SVCLASS_ID, add_avrtg },
+
+ { "UDIUE", UDI_MT_SVCLASS_ID, add_udi_ue },
+ { "UDITE", UDI_TA_SVCLASS_ID, add_udi_te },
+
+ { "SEMCHLA", 0x8e771301, add_semchla },
+
+ { "SR1", 0, add_sr1, sr1_uuid },
+ { "SYNCML", 0, add_syncml, syncmlc_uuid },
+ { "SYNCMLSERV", 0, NULL, syncmls_uuid },
+ { "ACTIVESYNC", 0, add_activesync, async_uuid },
+ { "HOTSYNC", 0, add_hotsync, hotsync_uuid },
+ { "PALMOS", 0, add_palmos, palmos_uuid },
+ { "NOKID", 0, add_nokiaid, nokid_uuid },
+ { "PCSUITE", 0, add_pcsuite, pcsuite_uuid },
+ { "NFTP", 0, NULL, nftp_uuid },
+ { "NSYNCML", 0, NULL, nsyncml_uuid },
+ { "NGAGE", 0, NULL, ngage_uuid },
+ { "APPLE", 0, add_apple, apple_uuid },
+
+ { "ISYNC", APPLE_AGENT_SVCLASS_ID, add_isync, },
+
+ { 0 }
+};
+
+/* Add local service */
+static int add_service(bdaddr_t *bdaddr, svc_info_t *si)
+{
+ sdp_session_t *sess;
+ int i, ret = -1;
+
+ if (!si->name)
+ return -1;
+
+ sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
+ if (!sess)
+ return -1;
+
+ for (i = 0; service[i].name; i++)
+ if (!strcasecmp(service[i].name, si->name)) {
+ if (service[i].add)
+ ret = service[i].add(sess, si);
+ goto done;
+ }
+
+ printf("Unknown service name: %s\n", si->name);
+
+done:
+ free(si->name);
+ sdp_close(sess);
+
+ return ret;
+}
+
+static struct option add_options[] = {
+ { "help", 0, 0, 'h' },
+ { "handle", 1, 0, 'r' },
+ { "psm", 1, 0, 'p' },
+ { "channel", 1, 0, 'c' },
+ { "network", 1, 0, 'n' },
+ { 0, 0, 0, 0 }
+};
+
+static char *add_help =
+ "Usage:\n"
+ "\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
+
+static int cmd_add(int argc, char **argv)
+{
+ svc_info_t si;
+ int opt;
+
+ memset(&si, 0, sizeof(si));
+ si.handle = 0xffffffff;
+
+ for_each_opt(opt, add_options, 0) {
+ switch (opt) {
+ case 'r':
+ if (strncasecmp(optarg, "0x", 2))
+ si.handle = atoi(optarg);
+ else
+ si.handle = strtol(optarg + 2, NULL, 16);
+ break;
+ case 'p':
+ if (strncasecmp(optarg, "0x", 2))
+ si.psm = atoi(optarg);
+ else
+ si.psm = strtol(optarg + 2, NULL, 16);
+ break;
+ case 'c':
+ if (strncasecmp(optarg, "0x", 2))
+ si.channel = atoi(optarg);
+ else
+ si.channel = strtol(optarg + 2, NULL, 16);
+ break;
+ case 'n':
+ if (strncasecmp(optarg, "0x", 2))
+ si.network = atoi(optarg);
+ else
+ si.network = strtol(optarg + 2, NULL, 16);
+ break;
+ default:
+ printf(add_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(add_help);
+ return -1;
+ }
+
+ si.name = strdup(argv[0]);
+
+ return add_service(0, &si);
+}
+
+/* Delete local service */
+static int del_service(bdaddr_t *bdaddr, void *arg)
+{
+ uint32_t handle, range = 0x0000ffff;
+ sdp_list_t *attr;
+ sdp_session_t *sess;
+ sdp_record_t *rec;
+
+ if (!arg) {
+ printf("Record handle was not specified.\n");
+ return -1;
+ }
+
+ sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
+ if (!sess) {
+ printf("No local SDP server!\n");
+ return -1;
+ }
+
+ handle = strtoul((char *)arg, 0, 16);
+ attr = sdp_list_append(0, &range);
+ rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr);
+ sdp_list_free(attr, 0);
+
+ if (!rec) {
+ printf("Service Record not found.\n");
+ sdp_close(sess);
+ return -1;
+ }
+
+ if (sdp_device_record_unregister(sess, &interface, rec)) {
+ printf("Failed to unregister service record: %s\n", strerror(errno));
+ sdp_close(sess);
+ return -1;
+ }
+
+ printf("Service Record deleted.\n");
+ sdp_close(sess);
+
+ return 0;
+}
+
+static struct option del_options[] = {
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *del_help =
+ "Usage:\n"
+ "\tdel record_handle\n";
+
+static int cmd_del(int argc, char **argv)
+{
+ int opt;
+
+ for_each_opt(opt, del_options, 0) {
+ switch (opt) {
+ default:
+ printf(del_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(del_help);
+ return -1;
+ }
+
+ return del_service(NULL, argv[0]);
+}
+
+/*
+ * Perform an inquiry and search/browse all peer found.
+ */
+static void inquiry(handler_t handler, void *arg)
+{
+ inquiry_info ii[20];
+ uint8_t count = 0;
+ int i;
+
+ printf("Inquiring ...\n");
+ if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
+ printf("Inquiry failed\n");
+ return;
+ }
+
+ for (i = 0; i < count; i++)
+ handler(&ii[i].bdaddr, arg);
+}
+
+static void doprintf(void *data, const char *str)
+{
+ printf(str);
+}
+
+/*
+ * Search for a specific SDP service
+ */
+static int do_search(bdaddr_t *bdaddr, struct search_context *context)
+{
+ sdp_list_t *attrid, *search, *seq, *next;
+ uint32_t range = 0x0000ffff;
+ char str[20];
+ sdp_session_t *sess;
+
+ if (!bdaddr) {
+ inquiry(do_search, context);
+ return 0;
+ }
+
+ sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
+ ba2str(bdaddr, str);
+ if (!sess) {
+ printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
+ return -1;
+ }
+
+ if (context->view != RAW_VIEW) {
+ if (context->svc)
+ printf("Searching for %s on %s ...\n", context->svc, str);
+ else
+ printf("Browsing %s ...\n", str);
+ }
+
+ attrid = sdp_list_append(0, &range);
+ search = sdp_list_append(0, &context->group);
+ if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) {
+ printf("Service Search failed: %s\n", strerror(errno));
+ sdp_close(sess);
+ return -1;
+ }
+ sdp_list_free(attrid, 0);
+ sdp_list_free(search, 0);
+
+ for (; seq; seq = next) {
+ sdp_record_t *rec = (sdp_record_t *) seq->data;
+ struct search_context sub_context;
+
+ switch (context->view) {
+ case DEFAULT_VIEW:
+ /* Display user friendly form */
+ print_service_attr(rec);
+ printf("\n");
+ break;
+ case TREE_VIEW:
+ /* Display full tree */
+ print_tree_attr(rec);
+ printf("\n");
+ break;
+ case XML_VIEW:
+ /* Display raw XML tree */
+ convert_sdp_record_to_xml(rec, 0, doprintf);
+ break;
+ default:
+ /* Display raw tree */
+ print_raw_attr(rec);
+ break;
+ }
+
+ if (sdp_get_group_id(rec, &sub_context.group) != -1) {
+ /* Set the subcontext for browsing the sub tree */
+ memcpy(&sub_context, context, sizeof(struct search_context));
+ /* Browse the next level down if not done */
+ if (sub_context.group.value.uuid16 != context->group.value.uuid16)
+ do_search(bdaddr, &sub_context);
+ }
+ next = seq->next;
+ free(seq);
+ sdp_record_free(rec);
+ }
+
+ sdp_close(sess);
+ return 0;
+}
+
+static struct option browse_options[] = {
+ { "help", 0, 0, 'h' },
+ { "tree", 0, 0, 't' },
+ { "raw", 0, 0, 'r' },
+ { "xml", 0, 0, 'x' },
+ { "uuid", 1, 0, 'u' },
+ { "l2cap", 0, 0, 'l' },
+ { 0, 0, 0, 0 }
+};
+
+static char *browse_help =
+ "Usage:\n"
+ "\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n";
+
+/*
+ * Browse the full SDP database (i.e. list all services starting from the
+ * root/top-level).
+ */
+static int cmd_browse(int argc, char **argv)
+{
+ struct search_context context;
+ int opt, num;
+
+ /* Initialise context */
+ memset(&context, '\0', sizeof(struct search_context));
+ /* We want to browse the top-level/root */
+ sdp_uuid16_create(&context.group, PUBLIC_BROWSE_GROUP);
+
+ for_each_opt(opt, browse_options, 0) {
+ switch (opt) {
+ case 't':
+ context.view = TREE_VIEW;
+ break;
+ case 'r':
+ context.view = RAW_VIEW;
+ break;
+ case 'x':
+ context.view = XML_VIEW;
+ break;
+ case 'u':
+ if (sscanf(optarg, "%i", &num) != 1 || num < 0 || num > 0xffff) {
+ printf("Invalid uuid %s\n", optarg);
+ return -1;
+ }
+ sdp_uuid16_create(&context.group, num);
+ break;
+ case 'l':
+ sdp_uuid16_create(&context.group, L2CAP_UUID);
+ break;
+ default:
+ printf(browse_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc >= 1) {
+ bdaddr_t bdaddr;
+ estr2ba(argv[0], &bdaddr);
+ return do_search(&bdaddr, &context);
+ }
+
+ return do_search(NULL, &context);
+}
+
+static struct option search_options[] = {
+ { "help", 0, 0, 'h' },
+ { "bdaddr", 1, 0, 'b' },
+ { "tree", 0, 0, 't' },
+ { "raw", 0, 0, 'r' },
+ { "xml", 0, 0, 'x' },
+ { 0, 0, 0, 0}
+};
+
+static char *search_help =
+ "Usage:\n"
+ "\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n"
+ "SERVICE is a name (string) or UUID (0x1002)\n";
+
+/*
+ * Search for a specific SDP service
+ *
+ * Note : we should support multiple services on the command line :
+ * sdptool search 0x0100 0x000f 0x1002
+ * (this would search a service supporting both L2CAP and BNEP directly in
+ * the top level browse group)
+ */
+static int cmd_search(int argc, char **argv)
+{
+ struct search_context context;
+ unsigned char *uuid = NULL;
+ uint32_t class = 0;
+ bdaddr_t bdaddr;
+ int has_addr = 0;
+ int i;
+ int opt;
+
+ /* Initialise context */
+ memset(&context, '\0', sizeof(struct search_context));
+
+ for_each_opt(opt, search_options, 0) {
+ switch (opt) {
+ case 'b':
+ estr2ba(optarg, &bdaddr);
+ has_addr = 1;
+ break;
+ case 't':
+ context.view = TREE_VIEW;
+ break;
+ case 'r':
+ context.view = RAW_VIEW;
+ break;
+ case 'x':
+ context.view = XML_VIEW;
+ break;
+ default:
+ printf(search_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(search_help);
+ return -1;
+ }
+
+ /* Note : we need to find a way to support search combining
+ * multiple services */
+ context.svc = strdup(argv[0]);
+ if (!strncasecmp(context.svc, "0x", 2)) {
+ int num;
+ /* This is a UUID16, just convert to int */
+ sscanf(context.svc + 2, "%X", &num);
+ class = num;
+ printf("Class 0x%X\n", class);
+ } else {
+ /* Convert class name to an UUID */
+
+ for (i = 0; service[i].name; i++)
+ if (strcasecmp(context.svc, service[i].name) == 0) {
+ class = service[i].class;
+ uuid = service[i].uuid;
+ break;
+ }
+ if (!class && !uuid) {
+ printf("Unknown service %s\n", context.svc);
+ return -1;
+ }
+ }
+
+ if (class) {
+ if (class & 0xffff0000)
+ sdp_uuid32_create(&context.group, class);
+ else {
+ uint16_t class16 = class & 0xffff;
+ sdp_uuid16_create(&context.group, class16);
+ }
+ } else
+ sdp_uuid128_create(&context.group, uuid);
+
+ if (has_addr)
+ return do_search(&bdaddr, &context);
+
+ return do_search(NULL, &context);
+}
+
+/*
+ * Show how to get a specific SDP record by its handle.
+ * Not really useful to the user, just show how it can be done...
+ */
+static int get_service(bdaddr_t *bdaddr, struct search_context *context, int quite)
+{
+ sdp_list_t *attrid;
+ uint32_t range = 0x0000ffff;
+ sdp_record_t *rec;
+ sdp_session_t *session = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
+
+ if (!session) {
+ char str[20];
+ ba2str(bdaddr, str);
+ printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
+ return -1;
+ }
+
+ attrid = sdp_list_append(0, &range);
+ rec = sdp_service_attr_req(session, context->handle, SDP_ATTR_REQ_RANGE, attrid);
+ sdp_list_free(attrid, 0);
+ sdp_close(session);
+
+ if (!rec) {
+ if (!quite) {
+ printf("Service get request failed.\n");
+ return -1;
+ } else
+ return 0;
+ }
+
+ switch (context->view) {
+ case DEFAULT_VIEW:
+ /* Display user friendly form */
+ print_service_attr(rec);
+ printf("\n");
+ break;
+ case TREE_VIEW:
+ /* Display full tree */
+ print_tree_attr(rec);
+ printf("\n");
+ break;
+ case XML_VIEW:
+ /* Display raw XML tree */
+ convert_sdp_record_to_xml(rec, 0, doprintf);
+ break;
+ default:
+ /* Display raw tree */
+ print_raw_attr(rec);
+ break;
+ }
+
+ sdp_record_free(rec);
+ return 0;
+}
+
+static struct option records_options[] = {
+ { "help", 0, 0, 'h' },
+ { "tree", 0, 0, 't' },
+ { "raw", 0, 0, 'r' },
+ { "xml", 0, 0, 'x' },
+ { 0, 0, 0, 0 }
+};
+
+static char *records_help =
+ "Usage:\n"
+ "\trecords [--tree] [--raw] [--xml] bdaddr\n";
+
+/*
+ * Request possible SDP service records
+ */
+static int cmd_records(int argc, char **argv)
+{
+ struct search_context context;
+ uint32_t base[] = { 0x10000, 0x10300, 0x10500,
+ 0x1002e, 0x110b, 0x90000, 0x2008000,
+ 0x4000000, 0x100000, 0x1000000, 0x4f491100 };
+ bdaddr_t bdaddr;
+ int i, n, opt, err = 0, num = 32;
+
+ /* Initialise context */
+ memset(&context, '\0', sizeof(struct search_context));
+
+ for_each_opt(opt, records_options, 0) {
+ switch (opt) {
+ case 't':
+ context.view = TREE_VIEW;
+ break;
+ case 'r':
+ context.view = RAW_VIEW;
+ break;
+ case 'x':
+ context.view = XML_VIEW;
+ break;
+ default:
+ printf(records_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(records_help);
+ return -1;
+ }
+
+ /* Convert command line parameters */
+ estr2ba(argv[0], &bdaddr);
+
+ for (i = 0; i < sizeof(base) / sizeof(uint32_t); i++)
+ for (n = 0; n < num; n++) {
+ context.handle = base[i] + n;
+ err = get_service(&bdaddr, &context, 1);
+ if (err < 0)
+ goto done;
+ }
+
+done:
+ return 0;
+}
+
+static struct option get_options[] = {
+ { "help", 0, 0, 'h' },
+ { "bdaddr", 1, 0, 'b' },
+ { "tree", 0, 0, 't' },
+ { "raw", 0, 0, 'r' },
+ { "xml", 0, 0, 'x' },
+ { 0, 0, 0, 0 }
+};
+
+static char *get_help =
+ "Usage:\n"
+ "\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n";
+
+/*
+ * Get a specific SDP record on the local SDP server
+ */
+static int cmd_get(int argc, char **argv)
+{
+ struct search_context context;
+ bdaddr_t bdaddr;
+ int has_addr = 0;
+ int opt;
+
+ /* Initialise context */
+ memset(&context, '\0', sizeof(struct search_context));
+
+ for_each_opt(opt, get_options, 0) {
+ switch (opt) {
+ case 'b':
+ estr2ba(optarg, &bdaddr);
+ has_addr = 1;
+ break;
+ case 't':
+ context.view = TREE_VIEW;
+ break;
+ case 'r':
+ context.view = RAW_VIEW;
+ break;
+ case 'x':
+ context.view = XML_VIEW;
+ break;
+ default:
+ printf(get_help);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ printf(get_help);
+ return -1;
+ }
+
+ /* Convert command line parameters */
+ context.handle = strtoul(argv[0], 0, 16);
+
+ return get_service(has_addr ? &bdaddr : BDADDR_LOCAL, &context, 0);
+}
+
+static struct {
+ char *cmd;
+ int (*func)(int argc, char **argv);
+ char *doc;
+} command[] = {
+ { "search", cmd_search, "Search for a service" },
+ { "browse", cmd_browse, "Browse all available services" },
+ { "records", cmd_records, "Request all records" },
+ { "add", cmd_add, "Add local service" },
+ { "del", cmd_del, "Delete local service" },
+ { "get", cmd_get, "Get local service" },
+ { "setattr", cmd_setattr, "Set/Add attribute to a SDP record" },
+ { "setseq", cmd_setseq, "Set/Add attribute sequence to a SDP record" },
+ { 0, 0, 0 }
+};
+
+static void usage(void)
+{
+ int i, pos = 0;
+
+ printf("sdptool - SDP tool v%s\n", VERSION);
+ printf("Usage:\n"
+ "\tsdptool [options] <command> [command parameters]\n");
+ printf("Options:\n"
+ "\t-h\t\tDisplay help\n"
+ "\t-i\t\tSpecify source interface\n");
+
+ printf("Commands:\n");
+ for (i = 0; command[i].cmd; i++)
+ printf("\t%-4s\t\t%s\n", command[i].cmd, command[i].doc);
+
+ printf("\nServices:\n\t");
+ for (i = 0; service[i].name; i++) {
+ printf("%s ", service[i].name);
+ pos += strlen(service[i].name) + 1;
+ if (pos > 60) {
+ printf("\n\t");
+ pos = 0;
+ }
+ }
+ printf("\n");
+}
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "device", 1, 0, 'i' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ int i, opt;
+
+ bacpy(&interface, BDADDR_ANY);
+
+ while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
+ switch(opt) {
+ case 'i':
+ if (!strncmp(optarg, "hci", 3))
+ hci_devba(atoi(optarg + 3), &interface);
+ else
+ str2ba(optarg, &interface);
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+
+ default:
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ for (i = 0; command[i].cmd; i++)
+ if (strncmp(command[i].cmd, argv[0], 4) == 0)
+ return command[i].func(argc, argv);
+
+ return 1;
+}
diff --git a/utils/tools/ubcsp.c b/utils/tools/ubcsp.c
new file mode 100644
index 00000000..6928da95
--- /dev/null
+++ b/utils/tools/ubcsp.c
@@ -0,0 +1,1193 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2005 CSR Ltd.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/** **/
+/** ubcsp,c **/
+/** **/
+/** MicroBCSP - a very low cost implementation of the BCSP protocol **/
+/** **/
+/*****************************************************************************/
+
+#include "ubcsp.h"
+
+#if SHOW_PACKET_ERRORS || SHOW_LE_STATES
+#include <stdio.h>
+#include <windows.h>
+#endif
+
+static uint16 ubcsp_calc_crc (uint8 ch, uint16 crc);
+static uint16 ubcsp_crc_reverse (uint16);
+
+/*****************************************************************************/
+/** **/
+/** Constant Data - ROM **/
+/** **/
+/*****************************************************************************/
+
+/* This is the storage for the link establishment messages */
+
+static const uint8 ubcsp_le_buffer[4][4] =
+ {
+ { 0xDA, 0xDC, 0xED, 0xED },
+ { 0xAC, 0xAF, 0xEF, 0xEE },
+ { 0xAD, 0xEF, 0xAC, 0xED },
+ { 0xDE, 0xAD, 0xD0, 0xD0 },
+ };
+
+/* These are the link establishment headers */
+/* The two version are for the CRC and non-CRC varients */
+
+#if UBCSP_CRC
+static const uint8 ubcsp_send_le_header[4] =
+ {
+ 0x40, 0x41, 0x00, 0x7E
+ };
+#else
+static const uint8 ubcsp_send_le_header[4] =
+ {
+ 0x00, 0x41, 0x00, 0xBE
+ };
+#endif
+
+/*****************************************************************************/
+/** **/
+/** Static Data - RAM **/
+/** **/
+/*****************************************************************************/
+
+/* This is the storage for all state data for ubcsp */
+
+static struct ubcsp_configuration ubcsp_config;
+
+/* This is the ACK packet header - this will be overwritten when
+ we create an ack packet */
+
+static uint8 ubcsp_send_ack_header[4] =
+ {
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+/* This is the deslip lookup table */
+
+static const uint8 ubcsp_deslip[2] =
+ {
+ SLIP_FRAME, SLIP_ESCAPE,
+ };
+
+/* This is a state machine table for link establishment */
+
+static uint8 next_le_packet[16] =
+ {
+ ubcsp_le_sync, // uninit
+ ubcsp_le_conf, // init
+ ubcsp_le_none, // active
+ ubcsp_le_none,
+ ubcsp_le_sync_resp, // sync_resp
+ ubcsp_le_sync_resp,
+ ubcsp_le_none,
+ ubcsp_le_none,
+ ubcsp_le_none, // conf_resp
+ ubcsp_le_conf_resp,
+ ubcsp_le_conf_resp,
+ ubcsp_le_none,
+ };
+
+/* This is the storage required for building send and crc data */
+
+static uint8 ubcsp_send_header[4];
+static uint8 ubcsp_send_crc[2];
+
+/* This is where the receive header is stored before the payload arrives */
+
+static uint8 ubcsp_receive_header[4];
+
+/*****************************************************************************/
+/** **/
+/** Code - ROM or RAM **/
+/** **/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_initialize **/
+/** **/
+/** This initializes the state of the ubcsp engine to a known values **/
+/** **/
+/*****************************************************************************/
+
+void ubcsp_initialize (void)
+{
+ ubcsp_config.ack_number = 0;
+ ubcsp_config.sequence_number = 0;
+ ubcsp_config.send_ptr = 0;
+ ubcsp_config.send_size = 0;
+ ubcsp_config.receive_index = -4;
+
+ ubcsp_config.delay = 0;
+
+#if SHOW_LE_STATES
+ printf ("Hello Link Uninitialized\n");
+#endif
+
+ ubcsp_config.link_establishment_state = ubcsp_le_uninitialized;
+ ubcsp_config.link_establishment_packet = ubcsp_le_sync;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_send_packet **/
+/** **/
+/** This sends a packet structure for sending to the ubcsp engine **/
+/** This can only be called when the activity indication from ubcsp_poll **/
+/** indicates that a packet can be sent with UBCSP_PACKET_SENT **/
+/** **/
+/*****************************************************************************/
+
+void ubcsp_send_packet (struct ubcsp_packet *send_packet)
+{
+ /* Initialize the send data to the packet we want to send */
+
+ ubcsp_config.send_packet = send_packet;
+
+ /* we cannot send the packet at the moment
+ when we can at the moment, just set things to 0 */
+
+ ubcsp_config.send_size = 0;
+ ubcsp_config.send_ptr = 0;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_receive_packet **/
+/** **/
+/** This sends a packet structure for receiving to the ubcsp engine **/
+/** This can only be called when the activity indication from ubcsp_poll **/
+/** indicates that a packet can be sent with UBCSP_PACKET_RECEIVED **/
+/** **/
+/*****************************************************************************/
+
+void ubcsp_receive_packet (struct ubcsp_packet *receive_packet)
+{
+ /* Initialize the receive data to the packet we want to receive */
+
+ ubcsp_config.receive_packet = receive_packet;
+
+ /* setup to receive the header first */
+
+ ubcsp_config.receive_index = -4;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_calc_crc **/
+/** **/
+/** Takes the next 8 bit value ch, and updates the crc with this value **/
+/** **/
+/*****************************************************************************/
+
+
+#ifdef UBCSP_CRC
+
+static uint16 ubcsp_calc_crc (uint8 ch, uint16 crc)
+{
+ /* Calculate the CRC using the above 16 entry lookup table */
+
+ static const uint16 crc_table[] =
+ {
+ 0x0000, 0x1081, 0x2102, 0x3183,
+ 0x4204, 0x5285, 0x6306, 0x7387,
+ 0x8408, 0x9489, 0xa50a, 0xb58b,
+ 0xc60c, 0xd68d, 0xe70e, 0xf78f
+ };
+
+ /* Do this four bits at a time - more code, less space */
+
+ crc = (crc >> 4) ^ crc_table[(crc ^ ch) & 0x000f];
+ crc = (crc >> 4) ^ crc_table[(crc ^ (ch >> 4)) & 0x000f];
+
+ return crc;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_crc_reverse **/
+/** **/
+/** Reserves the bits in crc and returns the new value **/
+/** **/
+/*****************************************************************************/
+
+static uint16 ubcsp_crc_reverse (uint16 crc)
+{
+ int32
+ b,
+ rev;
+
+ /* Reserse the bits to compute the actual CRC value */
+
+ for (b = 0, rev=0; b < 16; b++)
+ {
+ rev = rev << 1;
+ rev |= (crc & 1);
+ crc = crc >> 1;
+ }
+
+ return rev;
+}
+
+#endif
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_put_slip_uart **/
+/** **/
+/** Outputs a single octet to the uart **/
+/** If the octet needs to be escaped, then output the escape value **/
+/** and then store the second octet to be output later **/
+/** **/
+/*****************************************************************************/
+
+static void ubcsp_put_slip_uart (uint8 ch)
+{
+ /* output a single UART octet */
+
+ /* If it needs to be escaped, then output the escape octet
+ and set the send_slip_escape so that the next time we
+ output the second octet for the escape correctly.
+ This is done right at the top of ubcsp_poll */
+
+ if (ch == SLIP_FRAME)
+ {
+ put_uart (SLIP_ESCAPE);
+ ubcsp_config.send_slip_escape = SLIP_ESCAPE_FRAME;
+ }
+ else if (ch == SLIP_ESCAPE)
+ {
+ put_uart (SLIP_ESCAPE);
+ ubcsp_config.send_slip_escape = SLIP_ESCAPE_ESCAPE;
+ }
+ else
+ {
+ /* Not escaped, so just output octet */
+
+ put_uart (ch);
+ }
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_which_le_payload **/
+/** **/
+/** Check the payload of this packet, and determine which of the four **/
+/** link establishment packets this was. **/
+/** Can return 5 if it is not a valid link establishment packet **/
+/** **/
+/*****************************************************************************/
+
+static uint32 ubcsp_which_le_payload (const uint8 *payload)
+{
+ static int32
+ octet,
+ loop;
+
+ /* Search through the various link establishment payloads to find
+ which one we have received */
+
+ for (loop = 0; loop < 4; loop ++)
+ {
+ for (octet = 0; octet < 4; octet ++)
+ {
+ if (payload[octet] != ubcsp_le_buffer[loop][octet])
+ {
+ /* Bad match, just to loop again */
+ goto bad_match_loop;
+ }
+ }
+
+ /* All the octets matched, return the value */
+
+ return loop;
+
+ /* Jumps out of octet loop if we got a bad match */
+bad_match_loop:
+ {}
+ }
+
+ /* Non of the link establishment payloads matched - return invalid value */
+
+ return 5;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_recevied_packet **/
+/** **/
+/** This function is called when we have a SLIP END octet and a full **/
+/** packet header and possibly data in the receive packet **/
+/** **/
+/*****************************************************************************/
+
+static uint8 ubcsp_recevied_packet (void)
+{
+ static uint8
+ receive_crc,
+ receive_seq,
+ receive_ack,
+ activity;
+
+#if UBCSP_CRC
+ static int32
+ loop;
+
+ static uint16
+ crc;
+#endif
+
+ static uint16
+ length;
+
+ /* Keep track of what activity this received packet will cause */
+
+ activity = 0;
+
+ /*** Do all error checks that we can ***/
+
+ /* First check the header checksum */
+
+ if (((ubcsp_receive_header[0] + ubcsp_receive_header[1] + ubcsp_receive_header[2] + ubcsp_receive_header[3]) & 0xff) != 0xff)
+ {
+ /* Header Checksum Error */
+
+#if SHOW_PACKET_ERRORS
+ printf ("\n######################## Header Checksum Error %02X %02X %02X %02X\n",
+ ubcsp_receive_header[0],
+ ubcsp_receive_header[1],
+ ubcsp_receive_header[2],
+ ubcsp_receive_header[3]);
+#endif
+
+ /* If we have a header checksum error, send an ack in return
+ this gets a packet to be resent as quickly as possible */
+
+ ubcsp_config.send_ack = 1;
+
+ return activity;
+ }
+
+ /* Decode the received packets header */
+
+ ubcsp_config.receive_packet->reliable = (ubcsp_receive_header[0] & 0x80) >> 7;
+
+ receive_crc = (ubcsp_receive_header[0] & 0x40) >> 6;
+ receive_ack = (ubcsp_receive_header[0] & 0x38) >> 3;
+ receive_seq = (ubcsp_receive_header[0] & 0x07);
+
+ ubcsp_config.receive_packet->channel = (ubcsp_receive_header[1] & 0x0f);
+
+ length =
+ ((ubcsp_receive_header[1] & 0xf0) >> 4) |
+ (ubcsp_receive_header[2] << 4);
+
+#if SHOW_PACKET_ERRORS
+ if (ubcsp_config.receive_packet->reliable)
+ {
+ printf (" : %10d Recv SEQ: %d ACK %d\n",
+ GetTickCount () % 100000,
+ receive_seq,
+ receive_ack);
+ }
+ else if (ubcsp_config.receive_packet->channel != 1)
+ {
+ printf (" : %10d Recv ACK %d\n",
+ GetTickCount () % 100000,
+ receive_ack);
+ }
+#endif
+
+ /* Check for length errors */
+
+#if UBCSP_CRC
+ if (receive_crc)
+ {
+ /* If this packet had a CRC, then the length of the payload
+ should be 2 less than the received size of the payload */
+
+ if (length + 2 != ubcsp_config.receive_index)
+ {
+ /* Slip Length Error */
+
+#if SHOW_PACKET_ERRORS
+ printf ("\n######################## Slip Length Error (With CRC) %d,%d\n", length, ubcsp_config.receive_index - 2);
+#endif
+
+ /* If we have a payload length error, send an ack in return
+ this gets a packet to be resent as quickly as possible */
+
+ ubcsp_config.send_ack = 1;
+ return activity;
+ }
+
+ /* We have a CRC at the end of this packet */
+
+ ubcsp_config.receive_index -= 2;
+
+ /* Calculate the packet CRC */
+
+ crc = 0xffff;
+
+ /* CRC the packet header */
+
+ for (loop = 0; loop < 4; loop ++)
+ {
+ crc = ubcsp_calc_crc (ubcsp_receive_header[loop], crc);
+ }
+
+ /* CRC the packet payload - without the CRC bytes */
+
+ for (loop = 0; loop < ubcsp_config.receive_index; loop ++)
+ {
+ crc = ubcsp_calc_crc (ubcsp_config.receive_packet->payload[loop], crc);
+ }
+
+ /* Reverse the CRC */
+
+ crc = ubcsp_crc_reverse (crc);
+
+ /* Check the CRC is correct */
+
+ if
+ (
+ (((crc & 0xff00) >> 8) != ubcsp_config.receive_packet->payload[ubcsp_config.receive_index]) ||
+ ((crc & 0xff) != ubcsp_config.receive_packet->payload[ubcsp_config.receive_index + 1])
+ )
+ {
+#if SHOW_PACKET_ERRORS
+ printf ("\n######################## CRC Error\n");
+#endif
+
+ /* If we have a packet crc error, send an ack in return
+ this gets a packet to be resent as quickly as possible */
+
+ ubcsp_config.send_ack = 1;
+ return activity;
+ }
+ }
+ else
+ {
+#endif
+ /* No CRC present, so just check the length of payload with that received */
+
+ if (length != ubcsp_config.receive_index)
+ {
+ /* Slip Length Error */
+
+#if SHOW_PACKET_ERRORS
+ printf ("\n######################## Slip Length Error (No CRC) %d,%d\n", length, ubcsp_config.receive_index);
+#endif
+
+ /* If we have a payload length error, send an ack in return
+ this gets a packet to be resent as quickly as possible */
+
+ ubcsp_config.send_ack = 1;
+ return activity;
+ }
+#if UBCSP_CRC
+ }
+#endif
+
+ /*** We have a fully formed packet having passed all data integrity checks ***/
+
+ /* Check if we have an ACK for the last packet we sent */
+
+ if (receive_ack != ubcsp_config.sequence_number)
+ {
+ /* Since we only have a window size of 1, if the ACK is not equal to SEQ
+ then the packet was sent */
+
+ if
+ (
+ (ubcsp_config.send_packet) &&
+ (ubcsp_config.send_packet->reliable)
+ )
+ {
+ /* We had sent a reliable packet, so clear this packet
+ Then increament the sequence number for the next packet */
+
+ ubcsp_config.send_packet = 0;
+ ubcsp_config.sequence_number ++;
+ ubcsp_config.delay = 0;
+
+ /* Notify the caller that we have SENT a packet */
+
+ activity |= UBCSP_PACKET_SENT;
+ }
+ }
+
+ /*** Now we can concentrate of the packet we have received ***/
+
+ /* Check for Link Establishment packets */
+
+ if (ubcsp_config.receive_packet->channel == 1)
+ {
+ /* Link Establishment */
+
+ ubcsp_config.delay = 0;
+
+ /* Find which link establishment packet this payload means
+ This could return 5, meaning none */
+
+ switch (ubcsp_which_le_payload (ubcsp_config.receive_packet->payload))
+ {
+ case 0:
+ {
+ /* SYNC Recv'd */
+
+#if SHOW_LE_STATES
+ printf ("Recv SYNC\n");
+#endif
+
+ /* If we receive a SYNC, then we respond to it with a SYNC RESP
+ but only if we are not active.
+ If we are active, then we have a PEER RESET */
+
+ if (ubcsp_config.link_establishment_state < ubcsp_le_active)
+ {
+ ubcsp_config.link_establishment_resp = 1;
+ }
+ else
+ {
+ /* Peer reset !!!! */
+
+#if SHOW_LE_STATES
+ printf ("\n\n\n\n\nPEER RESET\n\n");
+#endif
+
+ /* Reinitialize the link */
+
+ ubcsp_initialize ();
+
+ /* Tell the host what has happened */
+
+ return UBCSP_PEER_RESET;
+ }
+ break;
+ }
+
+ case 1:
+ {
+ /* SYNC RESP Recv'd */
+
+#if SHOW_LE_STATES
+ printf ("Recv SYNC RESP\n");
+#endif
+
+ /* If we receive a SYNC RESP, push us into the initialized state */
+
+ if (ubcsp_config.link_establishment_state < ubcsp_le_initialized)
+ {
+#if SHOW_LE_STATES
+ printf ("Link Initialized\n");
+#endif
+ ubcsp_config.link_establishment_state = ubcsp_le_initialized;
+ }
+
+ break;
+ }
+
+ case 2:
+ {
+ /* CONF Recv'd */
+
+#if SHOW_LE_STATES
+ printf ("Recv CONF\n");
+#endif
+
+ /* If we receive a CONF, and we are initialized or active
+ then respond with a CONF RESP */
+
+ if (ubcsp_config.link_establishment_state >= ubcsp_le_initialized)
+ {
+ ubcsp_config.link_establishment_resp = 2;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ /* CONF RESP Recv'd */
+
+#if SHOW_LE_STATES
+ printf ("Recv CONF RESP\n");
+#endif
+
+ /* If we received a CONF RESP, then push us into the active state */
+
+ if (ubcsp_config.link_establishment_state < ubcsp_le_active)
+ {
+#if SHOW_LE_STATES
+ printf ("Link Active\n");
+#endif
+
+ ubcsp_config.link_establishment_state = ubcsp_le_active;
+ ubcsp_config.send_size = 0;
+
+ return activity | UBCSP_PACKET_SENT;
+ }
+
+ break;
+ }
+ }
+
+ /* We have finished processing Link Establishment packets */
+ }
+ else if (ubcsp_config.receive_index)
+ {
+ /* We have some payload data we need to process
+ but only if we are active - otherwise, we just ignore it */
+
+ if (ubcsp_config.link_establishment_state == ubcsp_le_active)
+ {
+ if (ubcsp_config.receive_packet->reliable)
+ {
+ /* If the packet we've just received was reliable
+ then send an ACK */
+
+ ubcsp_config.send_ack = 1;
+
+ /* We the sequence number we received is the same as
+ the last ACK we sent, then we have received a packet in sequence */
+
+ if (receive_seq == ubcsp_config.ack_number)
+ {
+ /* Increase the ACK number - which will be sent in the next ACK
+ or normal packet we send */
+
+ ubcsp_config.ack_number ++;
+
+ /* Set the values in the receive_packet structure, so the caller
+ knows how much data we have */
+
+ ubcsp_config.receive_packet->length = length;
+ ubcsp_config.receive_packet = 0;
+
+ /* Tell the caller that we have received a packet, and that it
+ will be ACK'ed */
+
+ activity |= UBCSP_PACKET_RECEIVED | UBCSP_PACKET_ACK;
+ }
+ }
+ else
+ {
+ /* Set the values in the receive_packet structure, so the caller
+ knows how much data we have */
+
+ ubcsp_config.receive_packet->length = length;
+ ubcsp_config.receive_packet = 0;
+
+ /* Tell the caller that we have received a packet */
+
+ activity |= UBCSP_PACKET_RECEIVED;
+ }
+ }
+ }
+
+ /* Just return any activity that occured */
+
+ return activity;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_setup_packet **/
+/** **/
+/** This function is called to setup a packet to be sent **/
+/** This allows just a header, or a header and payload to be sent **/
+/** It also allows the header checksum to be precalcuated **/
+/** or calculated here **/
+/** part1 is always 4 bytes **/
+/** **/
+/*****************************************************************************/
+
+static void ubcsp_setup_packet (uint8 *part1, uint8 calc, uint8 *part2, uint16 len2)
+{
+ /* If we need to calculate the checksum, do that now */
+
+ if (calc)
+ {
+ part1[3] =
+ ~(part1[0] + part1[1] + part1[2]);
+ }
+
+ /* Setup the header send pointer and size so we can clock this out */
+
+ ubcsp_config.send_ptr = part1;
+ ubcsp_config.send_size = 4;
+
+ /* Setup the payload send pointer and size */
+
+ ubcsp_config.next_send_ptr = part2;
+ ubcsp_config.next_send_size = len2;
+
+#if UBCSP_CRC
+ /* Initialize the crc as required */
+
+ ubcsp_config.send_crc = -1;
+
+ ubcsp_config.need_send_crc = 1;
+#endif
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_sent_packet **/
+/** **/
+/** Called when we have finished sending a packet **/
+/** If this packet was unreliable, then notify caller, and clear the data **/
+/** **/
+/*****************************************************************************/
+
+static uint8 ubcsp_sent_packet (void)
+{
+ if (ubcsp_config.send_packet)
+ {
+ if (!ubcsp_config.send_packet->reliable)
+ {
+ /* We had a packet sent that was unreliable */
+
+ /* Forget about this packet */
+
+ ubcsp_config.send_packet = 0;
+
+ /* Notify caller that they can send another one */
+
+ return UBCSP_PACKET_SENT;
+ }
+ }
+
+ /* We didn't have a packet, or it was reliable
+ Must wait for ACK before allowing another packet to be sent */
+
+ return 0;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_poll **/
+/** **/
+/** This is the main function for ubcsp **/
+/** It performs a number of tasks **/
+/** **/
+/** 1) Send another octet to the UART - escaping as required **/
+/** 2) Setup the payload to be sent after the header has been sent **/
+/** 3) Send the CRC for the packet if required **/
+/** **/
+/** 4) Calculate the next Link Establishment State **/
+/** 5) Send a Link Establishment packet **/
+/** 6) Send a normal packet if available **/
+/** 7) Send an ACK packet if required **/
+/** **/
+/** 8) Receive octets from UART and deslip them as required **/
+/** 9) Place received octets into receive header or receive payload buffer **/
+/** 10) Process received packet when SLIP_END is received **/
+/** **/
+/** 11) Keep track of ability of caller to delay recalling **/
+/** **/
+/*****************************************************************************/
+
+uint8 ubcsp_poll (uint8 *activity)
+{
+ uint8
+ delay = UBCSP_POLL_TIME_IMMEDIATE;
+
+ uint8
+ value;
+
+ /* Assume no activity to start with */
+
+ *activity = 0;
+
+ /* If we don't have to delay, then send something if we can */
+
+ if (!ubcsp_config.delay)
+ {
+ /* Do we have something we are sending to send */
+
+ if (ubcsp_config.send_size)
+ {
+ /* We have something to send so send it */
+
+ if (ubcsp_config.send_slip_escape)
+ {
+ /* Last time we send a SLIP_ESCAPE octet
+ this time send the second escape code */
+
+ put_uart (ubcsp_config.send_slip_escape);
+
+ ubcsp_config.send_slip_escape = 0;
+ }
+ else
+ {
+#if UBCSP_CRC
+ /* get the value to send, and calculate CRC as we go */
+
+ value = *ubcsp_config.send_ptr ++;
+
+ ubcsp_config.send_crc = ubcsp_calc_crc (value, ubcsp_config.send_crc);
+
+ /* Output the octet */
+
+ ubcsp_put_slip_uart (value);
+#else
+ /* Just output the octet*/
+
+ ubcsp_put_slip_uart (*ubcsp_config.send_ptr ++);
+#endif
+ }
+
+ /* If we did output a SLIP_ESCAPE, then don't process the end of a block */
+
+ if ((!ubcsp_config.send_slip_escape) && ((ubcsp_config.send_size = ubcsp_config.send_size - 1) == 0))
+ {
+ /*** We are at the end of a block - either header or payload ***/
+
+ /* setup the next block */
+
+ ubcsp_config.send_ptr = ubcsp_config.next_send_ptr;
+ ubcsp_config.send_size = ubcsp_config.next_send_size;
+ ubcsp_config.next_send_ptr = 0;
+ ubcsp_config.next_send_size = 0;
+
+#if UBCSP_CRC
+ /* If we have no successor block
+ then we might need to send the CRC */
+
+ if (!ubcsp_config.send_ptr)
+ {
+ if (ubcsp_config.need_send_crc)
+ {
+ /* reverse the CRC from what we computed along the way */
+
+ ubcsp_config.need_send_crc = 0;
+
+ ubcsp_config.send_crc = ubcsp_crc_reverse (ubcsp_config.send_crc);
+
+ /* Save in the send_crc buffer */
+
+ ubcsp_send_crc[0] = (uint8) (ubcsp_config.send_crc >> 8);
+ ubcsp_send_crc[1] = (uint8) ubcsp_config.send_crc;
+
+ /* Setup to send this buffer */
+
+ ubcsp_config.send_ptr = ubcsp_send_crc;
+ ubcsp_config.send_size = 2;
+ }
+ else
+ {
+ /* We don't need to send the crc
+ either we just have, or this packet doesn't include it */
+
+ /* Output the end of FRAME marker */
+
+ put_uart (SLIP_FRAME);
+
+ /* Check if this is an unreliable packet */
+
+ *activity |= ubcsp_sent_packet ();
+
+ /* We've sent the packet, so don't need to have be called quickly soon */
+
+ delay = UBCSP_POLL_TIME_DELAY;
+ }
+ }
+#else
+ /* If we have no successor block
+ then we might need to send the CRC */
+
+ if (!ubcsp_config.send_ptr)
+ {
+ /* Output the end of FRAME marker */
+
+ put_uart (SLIP_FRAME);
+
+ /* Check if this is an unreliable packet */
+
+ *activity |= ubcsp_sent_packet ();
+
+ /* We've sent the packet, so don't need to have be called quickly soon */
+
+ delay = UBCSP_POLL_TIME_DELAY;
+ }
+#endif
+ }
+ }
+ else if (ubcsp_config.link_establishment_packet == ubcsp_le_none)
+ {
+ /* We didn't have something to send
+ AND we have no Link Establishment packet to send */
+
+ if (ubcsp_config.link_establishment_resp & 2)
+ {
+ /* Send the start of FRAME packet */
+
+ put_uart (SLIP_FRAME);
+
+ /* We did require a RESP packet - so setup the send */
+
+ ubcsp_setup_packet ((uint8*) ubcsp_send_le_header, 0, (uint8*) ubcsp_le_buffer[ubcsp_le_conf_resp], 4);
+
+ /* We have now "sent" this packet */
+
+ ubcsp_config.link_establishment_resp = 0;
+ }
+ else if (ubcsp_config.send_packet)
+ {
+ /* There is a packet ready to be sent */
+
+ /* Send the start of FRAME packet */
+
+ put_uart (SLIP_FRAME);
+
+ /* Encode up the packet header using ACK and SEQ numbers */
+
+ ubcsp_send_header[0] =
+ (ubcsp_config.send_packet->reliable << 7) |
+#if UBCSP_CRC
+ 0x40 | /* Always use CRC's */
+#endif
+ (ubcsp_config.ack_number << 3) |
+ (ubcsp_config.sequence_number);
+
+ /* Encode up the packet header's channel and length */
+ ubcsp_send_header[1] =
+ (ubcsp_config.send_packet->channel & 0x0f) |
+ ((ubcsp_config.send_packet->length << 4) & 0xf0);
+
+ ubcsp_send_header[2] =
+ (ubcsp_config.send_packet->length >> 4) & 0xff;
+
+ /* Let the ubcsp_setup_packet function calculate the header checksum */
+
+ ubcsp_setup_packet ((uint8*) ubcsp_send_header, 1, ubcsp_config.send_packet->payload, ubcsp_config.send_packet->length);
+
+ /* Don't need to send an ACK - we just place on in this packet */
+
+ ubcsp_config.send_ack = 0;
+
+#if SHOW_PACKET_ERRORS
+ printf (" : %10d Send %d Ack %d\n",
+ GetTickCount () % 100000,
+ ubcsp_config.sequence_number,
+ ubcsp_config.ack_number);
+#endif
+ }
+ else if (ubcsp_config.send_ack)
+ {
+ /* Send the start of FRAME packet */
+
+ put_uart (SLIP_FRAME);
+
+#if SHOW_PACKET_ERRORS
+ printf (" : %10d Send ACK %d\n",
+ GetTickCount () % 100000,
+ ubcsp_config.ack_number);
+#endif
+
+ /* The ack packet is already computed apart from the first octet */
+
+ ubcsp_send_ack_header[0] =
+#if UBCSP_CRC
+ 0x40 |
+#endif
+ (ubcsp_config.ack_number << 3);
+
+ /* Let the ubcsp_setup_packet function calculate the header checksum */
+
+ ubcsp_setup_packet (ubcsp_send_ack_header, 1, 0, 0);
+
+ /* We've now sent the ack */
+
+ ubcsp_config.send_ack = 0;
+ }
+ else
+ {
+ /* We didn't have a Link Establishment response packet,
+ a normal packet or an ACK packet to send */
+
+ delay = UBCSP_POLL_TIME_DELAY;
+ }
+ }
+ else
+ {
+#if SHOW_PACKET_ERRORS
+// printf (" : %10d Send LE %d\n",
+// GetTickCount () % 100000,
+// ubcsp_config.link_establishment_packet);
+#endif
+
+ /* Send A Link Establishment Message */
+
+ put_uart (SLIP_FRAME);
+
+ /* Send the Link Establishment header followed by the
+ Link Establishment packet */
+
+ ubcsp_setup_packet ((uint8*) ubcsp_send_le_header, 0, (uint8*) ubcsp_le_buffer[ubcsp_config.link_establishment_packet], 4);
+
+ /* start sending immediately */
+
+ ubcsp_config.delay = 0;
+
+ /* workout what the next link establishment packet should be */
+
+ ubcsp_config.link_establishment_packet = next_le_packet[ubcsp_config.link_establishment_state + ubcsp_config.link_establishment_resp * 4];
+
+ /* We have now delt with any response packet that we needed */
+
+ ubcsp_config.link_establishment_resp = 0;
+
+ return 0;
+ }
+ }
+
+ /* We now need to receive any octets from the UART */
+
+ while ((ubcsp_config.receive_packet) && (get_uart (&value)))
+ {
+ /* If the last octet was SLIP_ESCAPE, then special processing is required */
+
+ if (ubcsp_config.receive_slip_escape)
+ {
+ /* WARNING - out of range values are not detected !!!
+ This will probably be caught with the checksum or CRC check */
+
+ value = ubcsp_deslip[value - SLIP_ESCAPE_FRAME];
+
+ ubcsp_config.receive_slip_escape = 0;
+ }
+ else
+ {
+ /* Check for the SLIP_FRAME octet - must be start or end of packet */
+ if (value == SLIP_FRAME)
+ {
+ /* If we had a full header then we have a packet */
+
+ if (ubcsp_config.receive_index >= 0)
+ {
+ /* process the received packet */
+
+ *activity |= ubcsp_recevied_packet ();
+
+ if (*activity & UBCSP_PACKET_ACK)
+ {
+ /* We need to ACK this packet, then don't delay its sending */
+ ubcsp_config.delay = 0;
+ }
+ }
+
+ /* Setup to receive the next packet */
+
+ ubcsp_config.receive_index = -4;
+
+ /* Ok, next octet */
+
+ goto finished_receive;
+ }
+ else if (value == SLIP_ESCAPE)
+ {
+ /* If we receive a SLIP_ESCAPE,
+ then remember to process the next special octet */
+
+ ubcsp_config.receive_slip_escape = 1;
+
+ goto finished_receive;
+ }
+ }
+
+ if (ubcsp_config.receive_index < 0)
+ {
+ /* We are still receiving the header */
+
+ ubcsp_receive_header[ubcsp_config.receive_index + 4] = value;
+
+ ubcsp_config.receive_index ++;
+ }
+ else if (ubcsp_config.receive_index < ubcsp_config.receive_packet->length)
+ {
+ /* We are receiving the payload */
+ /* We might stop comming here if we are receiving a
+ packet which is longer than the receive_packet->length
+ given by the host */
+
+ ubcsp_config.receive_packet->payload[ubcsp_config.receive_index] = value;
+
+ ubcsp_config.receive_index ++;
+ }
+
+finished_receive:
+ {
+ }
+ }
+
+ if (ubcsp_config.delay > 0)
+ {
+ /* We were delayed so delay some more
+ this could be cancelled if we received something */
+
+ ubcsp_config.delay --;
+ }
+ else
+ {
+ /* We had no delay, so use the delay we just decided to us */
+
+ ubcsp_config.delay = delay;
+ }
+
+ /* Report the current delay to the user */
+
+ return ubcsp_config.delay;
+}
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_end_of_functions **/
+/** **/
+/*****************************************************************************/
+
+/* This function is only included to allow for the size
+ of the code to be determined */
+
+void ubcsp_end_of_functions (void)
+{
+}
diff --git a/utils/tools/ubcsp.h b/utils/tools/ubcsp.h
new file mode 100644
index 00000000..6a74e9a1
--- /dev/null
+++ b/utils/tools/ubcsp.h
@@ -0,0 +1,208 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2000-2005 CSR Ltd.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef UBCSP_INCLUDE_H
+#define UBCSP_INCLUDE_H
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/** **/
+/** ubcsp.h **/
+/** **/
+/** MicroBCSP - a very low cost implementation of the BCSP protocol **/
+/** **/
+/*****************************************************************************/
+
+/* If we wish to use CRC's, then change 0 to 1 in the next line */
+#define UBCSP_CRC 1
+
+/* Define some basic types - change these for your architecture */
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef signed char int8;
+typedef signed short int16;
+typedef signed int int32;
+
+/* The defines below require a printf function to be available */
+
+/* Do we want to show packet errors in debug output */
+#define SHOW_PACKET_ERRORS 0
+
+/* Do we want to show Link Establishment State transitions in debug output */
+#define SHOW_LE_STATES 0
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_packet **/
+/** **/
+/** This is description of a bcsp packet for the upper layer **/
+/** **/
+/*****************************************************************************/
+
+struct ubcsp_packet
+{
+ uint8 channel; /* Which Channel this packet is to/from */
+ uint8 reliable; /* Is this packet reliable */
+ uint8 use_crc; /* Does this packet use CRC data protection */
+ uint16 length; /* What is the length of the payload data */
+ uint8 *payload; /* The payload data itself - size of length */
+};
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_configuration **/
+/** **/
+/** This is the main configuration of the ubcsp engine **/
+/** All state variables are stored in this structure **/
+/** **/
+/*****************************************************************************/
+
+enum ubcsp_link_establishment_state
+{
+ ubcsp_le_uninitialized,
+ ubcsp_le_initialized,
+ ubcsp_le_active
+};
+
+enum ubcsp_link_establishment_packet
+{
+ ubcsp_le_sync,
+ ubcsp_le_sync_resp,
+ ubcsp_le_conf,
+ ubcsp_le_conf_resp,
+ ubcsp_le_none
+};
+
+struct ubcsp_configuration
+{
+ uint8 link_establishment_state;
+ uint8 link_establishment_resp;
+ uint8 link_establishment_packet;
+
+ uint8 sequence_number:3;
+ uint8 ack_number:3;
+ uint8 send_ack;
+ struct ubcsp_packet *send_packet;
+ struct ubcsp_packet *receive_packet;
+
+ uint8 receive_header_checksum;
+ uint8 receive_slip_escape;
+ int32 receive_index;
+
+ uint8 send_header_checksum;
+#ifdef UBCSP_CRC
+ uint8 need_send_crc;
+ uint16 send_crc;
+#endif
+ uint8 send_slip_escape;
+
+ uint8 *send_ptr;
+ int32 send_size;
+ uint8 *next_send_ptr;
+ int32 next_send_size;
+
+ int8 delay;
+};
+
+/*****************************************************************************/
+/** **/
+/** ubcsp_poll sets activity from an OR of these flags **/
+/** **/
+/*****************************************************************************/
+
+#define UBCSP_PACKET_SENT 0x01
+#define UBCSP_PACKET_RECEIVED 0x02
+#define UBCSP_PEER_RESET 0x04
+#define UBCSP_PACKET_ACK 0x08
+
+/*****************************************************************************/
+/** **/
+/** This is the functional interface for ucbsp **/
+/** **/
+/*****************************************************************************/
+
+void ubcsp_initialize (void);
+void ubcsp_send_packet (struct ubcsp_packet *send_packet);
+void ubcsp_receive_packet (struct ubcsp_packet *receive_packet);
+uint8 ubcsp_poll (uint8 *activity);
+
+/*****************************************************************************/
+/** **/
+/** Slip Escape Values **/
+/** **/
+/*****************************************************************************/
+
+#define SLIP_FRAME 0xC0
+#define SLIP_ESCAPE 0xDB
+#define SLIP_ESCAPE_FRAME 0xDC
+#define SLIP_ESCAPE_ESCAPE 0xDD
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/** **/
+/** These functions need to be linked into your system **/
+/** **/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/** **/
+/** put_uart outputs a single octet over the UART Tx line **/
+/** **/
+/*****************************************************************************/
+
+extern void put_uart (uint8);
+
+/*****************************************************************************/
+/** **/
+/** get_uart receives a single octet over the UART Rx line **/
+/** if no octet is available, then this returns 0 **/
+/** if an octet was read, then this is returned in the argument and **/
+/** the function returns 1 **/
+/** **/
+/*****************************************************************************/
+
+extern uint8 get_uart (uint8 *);
+
+/*****************************************************************************/
+/** **/
+/** These defines should be changed to your systems concept of 100ms **/
+/** **/
+/*****************************************************************************/
+
+#define UBCSP_POLL_TIME_IMMEDIATE 0
+#define UBCSP_POLL_TIME_DELAY 25
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+#endif
diff --git a/utils/ylwrap b/utils/ylwrap
new file mode 100755
index 00000000..7278b6a3
--- /dev/null
+++ b/utils/ylwrap
@@ -0,0 +1,223 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2007-11-22.22
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005,
+# 2007 Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case "$1" in
+ '')
+ echo "$0: No files given. Try \`$0 --help' for more information." 1>&2
+ exit 1
+ ;;
+ --basedir)
+ basedir=$2
+ shift 2
+ ;;
+ -h|--h*)
+ cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+ INPUT is the input file
+ OUTPUT is one file PROG generates
+ DESIRED is the file we actually want instead of OUTPUT
+ PROGRAM is program to run
+ ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v|--v*)
+ echo "ylwrap $scriptversion"
+ exit $?
+ ;;
+esac
+
+
+# The input.
+input="$1"
+shift
+case "$input" in
+ [\\/]* | ?:[\\/]*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Relative path. Make it absolute.
+ input="`pwd`/$input"
+ ;;
+esac
+
+pairlist=
+while test "$#" -ne 0; do
+ if test "$1" = "--"; then
+ shift
+ break
+ fi
+ pairlist="$pairlist $1"
+ shift
+done
+
+# The program to run.
+prog="$1"
+shift
+# Make any relative path in $prog absolute.
+case "$prog" in
+ [\\/]* | ?:[\\/]*) ;;
+ *[\\/]*) prog="`pwd`/$prog" ;;
+esac
+
+# FIXME: add hostname here for parallel makes that run commands on
+# other machines. But that might take us over the 14-char limit.
+dirname=ylwrap$$
+trap "cd '`pwd`'; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+ 0) "$prog" "$input" ;;
+ *) "$prog" "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+ set X $pairlist
+ shift
+ first=yes
+ # Since DOS filename conventions don't allow two dots,
+ # the DOS version of Bison writes out y_tab.c instead of y.tab.c
+ # and y_tab.h instead of y.tab.h. Test to see if this is the case.
+ y_tab_nodot="no"
+ if test -f y_tab.c || test -f y_tab.h; then
+ y_tab_nodot="yes"
+ fi
+
+ # The directory holding the input.
+ input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
+ # Quote $INPUT_DIR so we can use it in a regexp.
+ # FIXME: really we should care about more than `.' and `\'.
+ input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'`
+
+ while test "$#" -ne 0; do
+ from="$1"
+ # Handle y_tab.c and y_tab.h output by DOS
+ if test $y_tab_nodot = "yes"; then
+ if test $from = "y.tab.c"; then
+ from="y_tab.c"
+ else
+ if test $from = "y.tab.h"; then
+ from="y_tab.h"
+ fi
+ fi
+ fi
+ if test -f "$from"; then
+ # If $2 is an absolute path name, then just use that,
+ # otherwise prepend `../'.
+ case "$2" in
+ [\\/]* | ?:[\\/]*) target="$2";;
+ *) target="../$2";;
+ esac
+
+ # We do not want to overwrite a header file if it hasn't
+ # changed. This avoid useless recompilations. However the
+ # parser itself (the first file) should always be updated,
+ # because it is the destination of the .y.c rule in the
+ # Makefile. Divert the output of all other files to a temporary
+ # file so we can compare them to existing versions.
+ if test $first = no; then
+ realtarget="$target"
+ target="tmp-`echo $target | sed s/.*[\\/]//g`"
+ fi
+ # Edit out `#line' or `#' directives.
+ #
+ # We don't want the resulting debug information to point at
+ # an absolute srcdir; it is better for it to just mention the
+ # .y file with no path.
+ #
+ # We want to use the real output file name, not yy.lex.c for
+ # instance.
+ #
+ # We want the include guards to be adjusted too.
+ FROM=`echo "$from" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+ TARGET=`echo "$2" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+
+ sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \
+ -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$?
+
+ # Check whether header files must be updated.
+ if test $first = no; then
+ if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+ echo "$2" is unchanged
+ rm -f "$target"
+ else
+ echo updating "$2"
+ mv -f "$target" "$realtarget"
+ fi
+ fi
+ else
+ # A missing file is only an error for the first file. This
+ # is a blatant hack to let us support using "yacc -d". If -d
+ # is not specified, we don't want an error when the header
+ # file is "missing".
+ if test $first = yes; then
+ ret=1
+ fi
+ fi
+ shift
+ shift
+ first=no
+ done
+else
+ ret=$?
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End: